ctdb: don't print OUTPUT: for DISABLED scripts
[metze/ctdb/wip.git] / tools / ctdb.c
index c48d5870954280ba624255ac9b01000655f85cda..204db1415be0f4f0d28144600cef6b1db21641f1 100644 (file)
@@ -31,7 +31,6 @@
 #include "../common/rb_tree.h"
 #include "db_wrap.h"
 
-
 #define ERR_TIMEOUT    20      /* timed out trying to reach node */
 #define ERR_NONODE     21      /* node does not exist */
 #define ERR_DISNODE    22      /* node is disconnected */
@@ -82,6 +81,10 @@ static void verify_node(struct ctdb_context *ctdb)
                DEBUG(DEBUG_ERR, ("Node %u does not exist\n", options.pnn));
                exit(ERR_NONODE);
        }
+       if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_DELETED) {
+               DEBUG(DEBUG_ERR, ("Node %u is DELETED\n", options.pnn));
+               exit(ERR_DISNODE);
+       }
        if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_DISCONNECTED) {
                DEBUG(DEBUG_ERR, ("Node %u is DISCONNECTED\n", options.pnn));
                exit(ERR_DISNODE);
@@ -209,6 +212,9 @@ static void show_statistics(struct ctdb_statistics *s)
                       preflen?0:4, "",
                       *(uint32_t *)(fields[i].offset+(uint8_t *)s));
        }
+       printf(" %-30s     %.6f sec\n", "max_reclock_ctdbd", s->reclock.ctdbd);
+       printf(" %-30s     %.6f sec\n", "max_reclock_recd", s->reclock.recd);
+
        printf(" %-30s     %.6f sec\n", "max_call_latency", s->max_call_latency);
        printf(" %-30s     %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency);
        printf(" %-30s     %.6f sec\n", "max_childwrite_latency", s->max_childwrite_latency);
@@ -312,7 +318,7 @@ static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv
        }
 
        if (options.machinereadable){
-               printf(":Current Node Time:Ctdb Start Time:Last Recovery Time:Last Recovery Duration:\n");
+               printf(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n");
                printf(":%u:%u:%u:%lf\n",
                        (unsigned int)uptime->current_time.tv_sec,
                        (unsigned int)uptime->ctdbd_start_time.tv_sec,
@@ -323,7 +329,7 @@ static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv
                return 0;
        }
 
-       printf("Current time of node  : %s", ctime(&uptime->current_time.tv_sec));
+       printf("Current time of node          :                %s", ctime(&uptime->current_time.tv_sec));
 
        tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
        seconds = tmp%60;
@@ -333,7 +339,7 @@ static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv
        hours   = tmp%24;
        tmp    /= 24;
        days    = tmp;
-       printf("Ctdbd start time      : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->ctdbd_start_time.tv_sec));
+       printf("Ctdbd start time              : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->ctdbd_start_time.tv_sec));
 
        tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
        seconds = tmp%60;
@@ -343,9 +349,9 @@ static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv
        hours   = tmp%24;
        tmp    /= 24;
        days    = tmp;
-       printf("Time of last recovery : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->last_recovery_finished.tv_sec));
+       printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->last_recovery_finished.tv_sec));
        
-       printf("Duration of last recovery : %lf seconds\n",
+       printf("Duration of last recovery/failover: %lf seconds\n",
                timeval_delta(&uptime->last_recovery_finished,
                              &uptime->last_recovery_started));
 
@@ -369,6 +375,110 @@ static int control_pnn(struct ctdb_context *ctdb, int argc, const char **argv)
        return 0;
 }
 
+
+struct pnn_node {
+       struct pnn_node *next;
+       const char *addr;
+       int pnn;
+};
+
+static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx)
+{
+       const char *nodes_list;
+       int nlines;
+       char **lines;
+       int i, pnn;
+       struct pnn_node *pnn_nodes = NULL;
+       struct pnn_node *pnn_node;
+       struct pnn_node *tmp_node;
+
+       /* read the nodes file */
+       nodes_list = getenv("CTDB_NODES");
+       if (nodes_list == NULL) {
+               nodes_list = "/etc/ctdb/nodes";
+       }
+       lines = file_lines_load(nodes_list, &nlines, mem_ctx);
+       if (lines == NULL) {
+               return NULL;
+       }
+       while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+               nlines--;
+       }
+       for (i=0, pnn=0; i<nlines; i++) {
+               char *node;
+
+               node = lines[i];
+               /* strip leading spaces */
+               while((*node == ' ') || (*node == '\t')) {
+                       node++;
+               }
+               if (*node == '#') {
+                       pnn++;
+                       continue;
+               }
+               if (strcmp(node, "") == 0) {
+                       continue;
+               }
+               pnn_node = talloc(mem_ctx, struct pnn_node);
+               pnn_node->pnn = pnn++;
+               pnn_node->addr = talloc_strdup(pnn_node, node);
+               pnn_node->next = pnn_nodes;
+               pnn_nodes = pnn_node;
+       }
+
+       /* swap them around so we return them in incrementing order */
+       pnn_node = pnn_nodes;
+       pnn_nodes = NULL;
+       while (pnn_node) {
+               tmp_node = pnn_node;
+               pnn_node = pnn_node->next;
+
+               tmp_node->next = pnn_nodes;
+               pnn_nodes = tmp_node;
+       }
+
+       return pnn_nodes;
+}
+
+/*
+  show the PNN of the current node
+  discover the pnn by loading the nodes file and try to bind to all
+  addresses one at a time until the ip address is found.
+ */
+static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       struct pnn_node *pnn_nodes;
+       struct pnn_node *pnn_node;
+
+       pnn_nodes = read_nodes_file(mem_ctx);
+       if (pnn_nodes == NULL) {
+               DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+               talloc_free(mem_ctx);
+               return -1;
+       }
+
+       for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
+               ctdb_sock_addr addr;
+
+               if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
+                       DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
+                       talloc_free(mem_ctx);
+                       return -1;
+               }
+
+               if (ctdb_sys_have_ip(&addr)) {
+                       printf("PNN:%d\n", pnn_node->pnn);
+                       talloc_free(mem_ctx);
+                       return 0;
+               }
+       }
+
+       printf("Failed to detect which PNN this node is\n");
+       talloc_free(mem_ctx);
+       return -1;
+}
+
 /*
   display remote ctdb status
  */
@@ -392,14 +502,18 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
        }
 
        if(options.machinereadable){
-               printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:\n");
+               printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:\n");
                for(i=0;i<nodemap->num;i++){
-                       printf(":%d:%s:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
+                       if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+                               continue;
+                       }
+                       printf(":%d:%s:%d:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
                                ctdb_addr_to_str(&nodemap->nodes[i].addr),
                               !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
                               !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
                               !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
-                              !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY));
+                              !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
+                              !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
                }
                return 0;
        }
@@ -414,9 +528,15 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
                        { NODE_FLAGS_PERMANENTLY_DISABLED,  "DISABLED" },
                        { NODE_FLAGS_BANNED,                "BANNED" },
                        { NODE_FLAGS_UNHEALTHY,             "UNHEALTHY" },
+                       { NODE_FLAGS_DELETED,               "DELETED" },
+                       { NODE_FLAGS_STOPPED,               "STOPPED" },
                };
                char *flags_str = NULL;
                int j;
+
+               if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+                       continue;
+               }
                for (j=0;j<ARRAY_SIZE(flag_names);j++) {
                        if (nodemap->nodes[i].flags & flag_names[j].flag) {
                                if (flags_str == NULL) {
@@ -472,42 +592,314 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
 }
 
 
+struct natgw_node {
+       struct natgw_node *next;
+       const char *addr;
+};
+
 /*
-  display the status of the monitoring scripts
+  display the list of nodes belonging to this natgw configuration
  */
-static int control_scriptstatus(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int i, ret;
-       struct ctdb_monitoring_wire *script_status;
+       const char *natgw_list;
+       int nlines;
+       char **lines;
+       struct natgw_node *natgw_nodes = NULL;
+       struct natgw_node *natgw_node;
+       struct ctdb_node_map *nodemap=NULL;
+
+
+       /* read the natgw nodes file into a linked list */
+       natgw_list = getenv("NATGW_NODES");
+       if (natgw_list == NULL) {
+               natgw_list = "/etc/ctdb/natgw_nodes";
+       }
+       lines = file_lines_load(natgw_list, &nlines, ctdb);
+       if (lines == NULL) {
+               ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list);
+               return -1;
+       }
+       while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+               nlines--;
+       }
+       for (i=0;i<nlines;i++) {
+               char *node;
+
+               node = lines[i];
+               /* strip leading spaces */
+               while((*node == ' ') || (*node == '\t')) {
+                       node++;
+               }
+               if (*node == '#') {
+                       continue;
+               }
+               if (strcmp(node, "") == 0) {
+                       continue;
+               }
+               natgw_node = talloc(ctdb, struct natgw_node);
+               natgw_node->addr = talloc_strdup(natgw_node, node);
+               CTDB_NO_MEMORY(ctdb, natgw_node->addr);
+               natgw_node->next = natgw_nodes;
+               natgw_nodes = natgw_node;
+       }
+
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
+               return ret;
+       }
+
+       i=0;
+       while(i<nodemap->num) {
+               for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) {
+                       if (!strcmp(natgw_node->addr, ctdb_addr_to_str(&nodemap->nodes[i].addr))) {
+                               break;
+                       }
+               }
+
+               /* this node was not in the natgw so we just remove it from
+                * the list
+                */
+               if ((natgw_node == NULL) 
+               ||  (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) ) {
+                       int j;
+
+                       for (j=i+1; j<nodemap->num; j++) {
+                               nodemap->nodes[j-1] = nodemap->nodes[j];
+                       }
+                       nodemap->num--;
+                       continue;
+               }
+
+               i++;
+       }               
+
+       /* pick a node to be natgwmaster
+        * we dont allow STOPPED, DELETED, BANNED or UNHEALTHY nodes to become the natgwmaster
+        */
+       for(i=0;i<nodemap->num;i++){
+               if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY))) {
+                       printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
+                       break;
+               }
+       }
+       /* we couldnt find any healthy node, try unhealthy ones */
+       if (i == nodemap->num) {
+               for(i=0;i<nodemap->num;i++){
+                       if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED))) {
+                               printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
+                               break;
+                       }
+               }
+       }
+       /* unless all nodes are STOPPED, when we pick one anyway */
+       if (i == nodemap->num) {
+               for(i=0;i<nodemap->num;i++){
+                       if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED))) {
+                               printf("%d %s\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr));
+                               break;
+                       }
+               }
+               /* or if we still can not find any */
+               if (i == nodemap->num) {
+                       printf("-1 0.0.0.0\n");
+               }
+       }
+
+       /* print the pruned list of nodes belonging to this natgw list */
+       for(i=0;i<nodemap->num;i++){
+               if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+                       continue;
+               }
+               printf(":%d:%s:%d:%d:%d:%d:%d\n", nodemap->nodes[i].pnn,
+                       ctdb_addr_to_str(&nodemap->nodes[i].addr),
+                      !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
+                      !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
+                      !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
+                      !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
+                      !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
+       }
+
+       return 0;
+}
 
-       ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, &script_status);
+/*
+  display the status of the scripts for monitoring (or other events)
+ */
+static int control_one_scriptstatus(struct ctdb_context *ctdb,
+                                   enum ctdb_eventscript_call type)
+{
+       struct ctdb_scripts_wire *script_status;
+       int ret, i;
+
+       ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to get script status from node %u\n", options.pnn));
                return ret;
        }
 
-       printf("%d scripts were executed last monitoring cycle\n", script_status->num_scripts);
+       if (script_status == NULL) {
+               if (!options.machinereadable) {
+                       printf("%s cycle never run\n",
+                              ctdb_eventscript_call_names[type]);
+               }
+               return 0;
+       }
+
+       if (!options.machinereadable) {
+               printf("%d scripts were executed last %s cycle\n",
+                      script_status->num_scripts,
+                      ctdb_eventscript_call_names[type]);
+       }
        for (i=0; i<script_status->num_scripts; i++) {
-               printf("%-20s Status:%s    ",
-                       script_status->scripts[i].name,
-                       script_status->scripts[i].timedout?"TIMEDOUT":script_status->scripts[i].status==0?"OK":"ERROR");
-               if (script_status->scripts[i].timedout == 0) {
+               const char *status = NULL;
+
+               switch (script_status->scripts[i].status) {
+               case -ETIME:
+                       status = "TIMEDOUT";
+                       break;
+               case -ENOEXEC:
+                       status = "DISABLED";
+                       break;
+               case 0:
+                       status = "OK";
+                       break;
+               default:
+                       if (script_status->scripts[i].status > 0)
+                               status = "ERROR";
+                       break;
+               }
+               if (options.machinereadable) {
+                       printf("%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n",
+                              ctdb_eventscript_call_names[type],
+                              script_status->scripts[i].name,
+                              script_status->scripts[i].status,
+                              status,
+                              (long)script_status->scripts[i].start.tv_sec,
+                              (long)script_status->scripts[i].start.tv_usec,
+                              (long)script_status->scripts[i].finished.tv_sec,
+                              (long)script_status->scripts[i].finished.tv_usec,
+                              script_status->scripts[i].output);
+                       continue;
+               }
+               if (status)
+                       printf("%-20s Status:%s    ",
+                              script_status->scripts[i].name, status);
+               else
+                       /* Some other error, eg from stat. */
+                       printf("%-20s Status:CANNOT RUN (%s)",
+                              script_status->scripts[i].name,
+                              strerror(-script_status->scripts[i].status));
+
+               if (script_status->scripts[i].status >= 0) {
                        printf("Duration:%.3lf ",
                        timeval_delta(&script_status->scripts[i].finished,
                              &script_status->scripts[i].start));
                }
-               printf("%s",
-                       ctime(&script_status->scripts[i].start.tv_sec));
-               if ((script_status->scripts[i].timedout != 0)
-               ||  (script_status->scripts[i].status != 0) ) {
-                       printf("   OUTPUT:%s\n",
-                               script_status->scripts[i].output);
+               if (script_status->scripts[i].status != -ENOEXEC) {
+                       printf("%s",
+                              ctime(&script_status->scripts[i].start.tv_sec));
+                       if (script_status->scripts[i].status != 0) {
+                               printf("   OUTPUT:%s\n",
+                                      script_status->scripts[i].output);
+                       }
+               } else {
+                       printf("\n");
+               }
+       }
+       return 0;
+}
+
+
+static int control_scriptstatus(struct ctdb_context *ctdb,
+                               int argc, const char **argv)
+{
+       int ret;
+       enum ctdb_eventscript_call type, min, max;
+       const char *arg;
+
+       if (argc > 1) {
+               DEBUG(DEBUG_ERR, ("Unknown arguments to scriptstatus\n"));
+               return -1;
+       }
+
+       if (argc == 0)
+               arg = ctdb_eventscript_call_names[CTDB_EVENT_MONITOR];
+       else
+               arg = argv[0];
+
+       for (type = 0; type < CTDB_EVENT_MAX; type++) {
+               if (strcmp(arg, ctdb_eventscript_call_names[type]) == 0) {
+                       min = type;
+                       max = type+1;
+                       break;
+               }
+       }
+       if (type == CTDB_EVENT_MAX) {
+               if (strcmp(arg, "all") == 0) {
+                       min = 0;
+                       max = CTDB_EVENT_MAX;
+               } else {
+                       DEBUG(DEBUG_ERR, ("Unknown event type %s\n", argv[0]));
+                       return -1;
+               }
+       }
+
+       if (options.machinereadable) {
+               printf(":Type:Name:Code:Status:Start:End:Error Output...:\n");
+       }
+
+       for (type = min; type < max; type++) {
+               ret = control_one_scriptstatus(ctdb, type);
+               if (ret != 0) {
+                       return ret;
                }
        }
 
        return 0;
 }
-       
+
+/*
+  enable an eventscript
+ */
+static int control_enablescript(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+
+       if (argc < 1) {
+               usage();
+       }
+
+       ret = ctdb_ctrl_enablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]);
+       if (ret != 0) {
+         DEBUG(DEBUG_ERR, ("Unable to enable script %s on node %u\n", argv[0], options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+  disable an eventscript
+ */
+static int control_disablescript(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+
+       if (argc < 1) {
+               usage();
+       }
+
+       ret = ctdb_ctrl_disablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]);
+       if (ret != 0) {
+         DEBUG(DEBUG_ERR, ("Unable to disable script %s on node %u\n", argv[0], options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
 
 /*
   display the pnn of the recovery master
@@ -540,7 +932,7 @@ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char *
                usage();
        }
 
-       if (parse_ip(argv[0], NULL, &addr) == 0) {
+       if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
                DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
                return -1;
        }
@@ -563,37 +955,84 @@ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char *
        return 0;
 }
 
-/* send a release ip to all nodes */
-static int control_send_release(struct ctdb_context *ctdb, uint32_t pnn,
-ctdb_sock_addr *addr)
+
+
+static int move_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn)
 {
-       int ret;
-       struct ctdb_public_ip pip;
+       struct ctdb_all_public_ips *ips;
+       struct ctdb_public_ip ip;
+       int i, ret;
+       uint32_t *nodes;
+       uint32_t disable_time;
        TDB_DATA data;
        struct ctdb_node_map *nodemap=NULL;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+       disable_time = 30;
+       data.dptr  = (uint8_t*)&disable_time;
+       data.dsize = sizeof(disable_time);
+       ret = ctdb_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_DISABLE_IP_CHECK, data);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
-               return ret;
+               DEBUG(DEBUG_ERR,("Failed to send message to disable ipcheck\n"));
+               return -1;
        }
 
-       /* send a moveip message to the recovery master */
-       pip.pnn    = pnn;
-       pip.addr   = *addr;
-       data.dsize = sizeof(pip);
-       data.dptr  = (unsigned char *)&pip;
 
 
-       /* send release ip to all nodes */
-       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP,
-                       list_of_active_nodes(ctdb, nodemap, ctdb, true),
-                       TIMELIMIT(), false, data,
-                       NULL, NULL, NULL) != 0) {
-               DEBUG(DEBUG_ERR, (__location__ " Unable to send 'ReleaseIP' to all nodes.\n"));
+       /* read the public ip list from the node */
+       ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), pnn, ctdb, &ips);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", pnn));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       for (i=0;i<ips->num;i++) {
+               if (ctdb_same_ip(addr, &ips->ips[i].addr)) {
+                       break;
+               }
+       }
+       if (i==ips->num) {
+               DEBUG(DEBUG_ERR, ("Node %u can not host ip address '%s'\n",
+                       pnn, ctdb_addr_to_str(addr)));
+               talloc_free(tmp_ctx);
                return -1;
        }
 
+       ip.pnn  = pnn;
+       ip.addr = *addr;
+
+       data.dptr  = (uint8_t *)&ip;
+       data.dsize = sizeof(ip);
+
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+               nodes = list_of_active_nodes_except_pnn(ctdb, nodemap, tmp_ctx, pnn);
+       ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP,
+                                       nodes, 0,
+                                       TIMELIMIT(),
+                                       false, data,
+                                       NULL, NULL,
+                                       NULL);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Failed to release IP on nodes\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       ret = ctdb_ctrl_takeover_ip(ctdb, TIMELIMIT(), pnn, &ip);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Failed to take over IP on node %d\n", pnn));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
        return 0;
 }
 
@@ -604,15 +1043,13 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
 {
        uint32_t pnn;
        ctdb_sock_addr addr;
-       uint32_t value;
-       struct ctdb_all_public_ips *ips;
-       int i, ret;
 
        if (argc < 2) {
                usage();
+               return -1;
        }
 
-       if (parse_ip(argv[0], NULL,  &addr) == 0) {
+       if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
                DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
                return -1;
        }
@@ -623,52 +1060,8 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
                return -1;
        }
 
-       ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, "DeterministicIPs", &value);
-       if (ret == -1) {
-               DEBUG(DEBUG_ERR, ("Unable to get tunable variable 'DeterministicIPs' from local node\n"));
-               return -1;
-       }
-       if (value != 0) {
-               DEBUG(DEBUG_ERR, ("The tunable 'DeterministicIPs' is set. You can only move ip addresses when this feature is disabled\n"));
-               return -1;
-       }
-
-       ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, "NoIPFailback", &value);
-       if (ret == -1) {
-               DEBUG(DEBUG_ERR, ("Unable to get tunable variable 'NoIPFailback' from local node\n"));
-               return -1;
-       }
-       if (value == 0) {
-               DEBUG(DEBUG_ERR, ("The tunable 'NoIPFailback' is NOT set. You can only move ip addresses when this feature is enabled\n"));
-               return -1;
-       }
-
-       /* read the public ip list from the node */
-       ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), pnn, ctdb, &ips);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", pnn));
-               return -1;
-       }
-
-       for (i=0;i<ips->num;i++) {
-               if (ctdb_same_ip(&addr, &ips->ips[i].addr)) {
-                       break;
-               }
-       }
-       if (i==ips->num) {
-               DEBUG(DEBUG_ERR, ("Node %u can not host ip address '%s'\n",
-                       pnn, ctdb_addr_to_str(&addr)));
-               return -1;
-       }
-       if (ips->ips[i].pnn == pnn) {
-               DEBUG(DEBUG_ERR, ("Host %u is already hosting '%s'\n",
-                       pnn, ctdb_addr_to_str(&ips->ips[i].addr)));
-               return -1;
-       }
-
-       ret = control_send_release(ctdb, pnn, &ips->ips[i].addr);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Failed to send 'change ip' to all nodes\n"));;
+       if (move_ip(ctdb, &addr, pnn) != 0) {
+               DEBUG(DEBUG_ERR,("Failed to move ip to node %d\n", pnn));
                return -1;
        }
 
@@ -741,6 +1134,9 @@ control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struc
        ip_tree = trbt_create(tmp_ctx, 0);
 
        for(i=0;i<nodemap->num;i++){
+               if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+                       continue;
+               }
                if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
                        continue;
                }
@@ -802,7 +1198,7 @@ find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
        }
 
        for(i=0;i<nodemap->num;i++){
-               if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+               if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
                        continue;
                }
                if (nodemap->nodes[i].pnn == options.pnn) {
@@ -836,12 +1232,14 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int i, ret;
        int len;
+       uint32_t pnn;
        unsigned mask;
        ctdb_sock_addr addr;
        struct ctdb_control_ip_iface *pub;
        TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
        struct ctdb_all_public_ips *ips;
 
+
        if (argc != 2) {
                talloc_free(tmp_ctx);
                usage();
@@ -861,6 +1259,15 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
        }
 
 
+       /* check if some other node is already serving this ip, if not,
+        * we will claim it
+        */
+       for (i=0;i<ips->num;i++) {
+               if (ctdb_same_ip(&addr, &ips->ips[i].addr)) {
+                       break;
+               }
+       }
+
        len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]) + 1;
        pub = talloc_size(tmp_ctx, len); 
        CTDB_NO_MEMORY(ctdb, pub);
@@ -877,24 +1284,15 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
                return ret;
        }
 
-
-       /* check if some other node is already serving this ip, if not,
-        * we will claim it
-        */
-       for (i=0;i<ips->num;i++) {
-               if (ctdb_same_ip(&addr, &ips->ips[i].addr)) {
-                       break;
-               }
-       }
-       /* no one has this ip so we claim it */
        if (i == ips->num) {
-               ret = control_send_release(ctdb, options.pnn, &addr);
+               /* no one has this ip so we claim it */
+               pnn  = options.pnn;
        } else {
-               ret = control_send_release(ctdb, ips->ips[i].pnn, &addr);
+               pnn  = ips->ips[i].pnn;
        }
 
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Failed to send 'change ip' to all nodes\n"));
+       if (move_ip(ctdb, &addr, pnn) != 0) {
+               DEBUG(DEBUG_ERR,("Failed to move ip to node %d\n", pnn));
                return -1;
        }
 
@@ -919,7 +1317,7 @@ static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **a
 
        /* remove it from the nodes that are not hosting the ip currently */
        for(i=0;i<nodemap->num;i++){
-               if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+               if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
                        continue;
                }
                if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
@@ -947,7 +1345,7 @@ static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **a
 
        /* remove it from every node (also the one hosting it) */
        for(i=0;i<nodemap->num;i++){
-               if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+               if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
                        continue;
                }
                if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
@@ -988,7 +1386,7 @@ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
                usage();
        }
 
-       if (parse_ip(argv[0], NULL, &addr) == 0) {
+       if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
                DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
                return -1;
        }
@@ -1024,9 +1422,9 @@ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
        if (ips->ips[i].pnn == options.pnn) {
                ret = find_other_host_for_public_ip(ctdb, &addr);
                if (ret != -1) {
-                       ret = control_send_release(ctdb, ret, &addr);
-                       if (ret != 0) {
-                               DEBUG(DEBUG_ERR, ("Failed to migrate this ip to another node. Use moveip of recover to reassign this address to a node\n"));
+                       if (move_ip(ctdb, &addr, ret) != 0) {
+                               DEBUG(DEBUG_ERR,("Failed to move ip to node %d\n", ret));
+                               return -1;
                        }
                }
        }
@@ -1086,7 +1484,7 @@ static int control_gratious_arp(struct ctdb_context *ctdb, int argc, const char
                usage();
        }
 
-       if (!parse_ip(argv[0], NULL, &addr)) {
+       if (!parse_ip(argv[0], NULL, 0, &addr)) {
                DEBUG(DEBUG_ERR, ("Bad IP '%s'\n", argv[0]));
                return -1;
        }
@@ -1280,33 +1678,254 @@ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
 }
 
 /*
-  display pid of a ctdb daemon
+  display pid of a ctdb daemon
+ */
+static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t pid;
+       int ret;
+
+       ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.pnn, &pid);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get daemon pid from node %u\n", options.pnn));
+               return ret;
+       }
+       printf("Pid:%d\n", pid);
+
+       return 0;
+}
+
+/*
+  handler for receiving the response to ipreallocate
+*/
+static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+                            TDB_DATA data, void *private_data)
+{
+       exit(0);
+}
+
+static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+{
+       struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+
+       event_add_timed(ctdb->ev, ctdb, 
+                               timeval_current_ofs(1, 0),
+                               ctdb_every_second, ctdb);
+}
+
+/*
+  ask the recovery daemon on the recovery master to perform a ip reallocation
+ */
+static int control_ipreallocate(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int i, ret;
+       TDB_DATA data;
+       struct takeover_run_reply rd;
+       uint32_t recmaster;
+       struct ctdb_node_map *nodemap=NULL;
+       int retries=0;
+       struct timeval tv = timeval_current();
+
+       /* we need some events to trigger so we can timeout and restart
+          the loop
+       */
+       event_add_timed(ctdb->ev, ctdb, 
+                               timeval_current_ofs(1, 0),
+                               ctdb_every_second, ctdb);
+
+       rd.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+       if (rd.pnn == -1) {
+               DEBUG(DEBUG_ERR, ("Failed to get pnn of local node\n"));
+               return -1;
+       }
+       rd.srvid = getpid();
+
+       /* register a message port for receiveing the reply so that we
+          can receive the reply
+       */
+       ctdb_set_message_handler(ctdb, rd.srvid, ip_reallocate_handler, NULL);
+
+       data.dptr = (uint8_t *)&rd;
+       data.dsize = sizeof(rd);
+
+again:
+       if (retries>5) {
+               DEBUG(DEBUG_ERR,("Failed waiting for cluster convergense\n"));
+               exit(10);
+       }
+
+       /* check that there are valid nodes available */
+       if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               exit(10);
+       }
+       for (i=0; i<nodemap->num;i++) {
+               if ((nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) == 0) {
+                       break;
+               }
+       }
+       if (i==nodemap->num) {
+               DEBUG(DEBUG_ERR,("No recmaster available, no need to wait for cluster convergence\n"));
+               return 0;
+       }
+
+
+       ret = ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), options.pnn, &recmaster);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+               return ret;
+       }
+
+       /* verify the node exists */
+       if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), recmaster, ctdb, &nodemap) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               exit(10);
+       }
+
+
+       /* check tha there are nodes available that can act as a recmaster */
+       for (i=0; i<nodemap->num; i++) {
+               if (nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+                       continue;
+               }
+               break;
+       }
+       if (i == nodemap->num) {
+               DEBUG(DEBUG_ERR,("No possible nodes to host addresses.\n"));
+               return 0;
+       }
+
+       /* verify the recovery master is not STOPPED, nor BANNED */
+       if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+               DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
+               retries++;
+               sleep(1);
+               goto again;
+       } 
+
+       
+       /* verify the recovery master is not STOPPED, nor BANNED */
+       if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+               DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
+               retries++;
+               sleep(1);
+               goto again;
+       } 
+
+       ret = ctdb_send_message(ctdb, recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Failed to send ip takeover run request message to %u\n", options.pnn));
+               return -1;
+       }
+
+       tv = timeval_current();
+       /* this loop will terminate when we have received the reply */
+       while (timeval_elapsed(&tv) < 3.0) {    
+               event_loop_once(ctdb->ev);
+       }
+
+       DEBUG(DEBUG_INFO,("Timed out waiting for recmaster ipreallocate. Trying again\n"));
+       retries++;
+       sleep(1);
+       goto again;
+
+       return 0;
+}
+
+
+/*
+  disable a remote node
+ */
+static int control_disable(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       struct ctdb_node_map *nodemap=NULL;
+
+       do {
+               ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, NODE_FLAGS_PERMANENTLY_DISABLED, 0);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to disable node %u\n", options.pnn));
+                       return ret;
+               }
+
+               sleep(1);
+
+               /* read the nodemap and verify the change took effect */
+               if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+                       exit(10);
+               }
+
+       } while (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED));
+       ret = control_ipreallocate(ctdb, argc, argv);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+  enable a disabled remote node
  */
-static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_enable(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       uint32_t pid;
        int ret;
 
-       ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.pnn, &pid);
+       struct ctdb_node_map *nodemap=NULL;
+
+       do {
+               ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, 0, NODE_FLAGS_PERMANENTLY_DISABLED);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to enable node %u\n", options.pnn));
+                       return ret;
+               }
+
+               sleep(1);
+
+               /* read the nodemap and verify the change took effect */
+               if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+                       exit(10);
+               }
+
+       } while (nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED);
+       ret = control_ipreallocate(ctdb, argc, argv);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get daemon pid from node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
                return ret;
        }
-       printf("Pid:%d\n", pid);
 
        return 0;
 }
 
 /*
-  disable a remote node
+  stop a remote node
  */
-static int control_disable(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_stop(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
+       struct ctdb_node_map *nodemap=NULL;
+
+       do {
+               ret = ctdb_ctrl_stop_node(ctdb, TIMELIMIT(), options.pnn);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to stop node %u   try again\n", options.pnn));
+               }
+       
+               sleep(1);
+
+               /* read the nodemap and verify the change took effect */
+               if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+                       exit(10);
+               }
 
-       ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, NODE_FLAGS_PERMANENTLY_DISABLED, 0);
+       } while (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_STOPPED));
+       ret = control_ipreallocate(ctdb, argc, argv);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to disable node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
                return ret;
        }
 
@@ -1314,15 +1933,33 @@ static int control_disable(struct ctdb_context *ctdb, int argc, const char **arg
 }
 
 /*
-  enable a disabled remote node
+  restart a stopped remote node
  */
-static int control_enable(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_continue(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
 
-       ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, 0, NODE_FLAGS_PERMANENTLY_DISABLED);
+       struct ctdb_node_map *nodemap=NULL;
+
+       do {
+               ret = ctdb_ctrl_continue_node(ctdb, TIMELIMIT(), options.pnn);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to continue node %u\n", options.pnn));
+                       return ret;
+               }
+       
+               sleep(1);
+
+               /* read the nodemap and verify the change took effect */
+               if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+                       exit(10);
+               }
+
+       } while (nodemap->nodes[options.pnn].flags & NODE_FLAGS_STOPPED);
+       ret = control_ipreallocate(ctdb, argc, argv);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to enable node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
                return ret;
        }
 
@@ -1378,20 +2015,13 @@ static uint32_t get_generation(struct ctdb_context *ctdb)
 static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
-       struct ctdb_ban_info b;
-       TDB_DATA data;
-       uint32_t ban_time;
        struct ctdb_node_map *nodemap=NULL;
-       uint32_t generation, next_generation;
+       struct ctdb_ban_time bantime;
 
        if (argc < 1) {
                usage();
        }
        
-       /* record the current generation number */
-       generation = get_generation(ctdb);
-
-
        /* verify the node exists */
        ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
        if (ret != 0) {
@@ -1404,27 +2034,19 @@ static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
                return -1;
        }
 
-       ban_time = strtoul(argv[0], NULL, 0);
-
-       b.pnn = options.pnn;
-       b.ban_time = ban_time;
+       bantime.pnn  = options.pnn;
+       bantime.time = strtoul(argv[0], NULL, 0);
 
-       data.dptr = (uint8_t *)&b;
-       data.dsize = sizeof(b);
-
-       ret = ctdb_send_message(ctdb, options.pnn, CTDB_SRVID_BAN_NODE, data);
+       ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, &bantime);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR,("Failed to ban node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR,("Banning node %d for %d seconds failed.\n", bantime.pnn, bantime.time));
                return -1;
-       }
+       }       
 
-       /* wait until we are in a new generation */
-       while (1) {
-               next_generation = get_generation(ctdb);
-               if (next_generation != generation) {
-                       return 0;
-               }
-               sleep(1);
+       ret = control_ipreallocate(ctdb, argc, argv);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+               return ret;
        }
 
        return 0;
@@ -1437,34 +2059,71 @@ static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
 static int control_unban(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
-       TDB_DATA data;
-       uint32_t generation, next_generation;
+       struct ctdb_node_map *nodemap=NULL;
+       struct ctdb_ban_time bantime;
 
-       /* record the current generation number */
-       generation = get_generation(ctdb);
+       /* verify the node exists */
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               return ret;
+       }
 
-       data.dptr = (uint8_t *)&options.pnn;
-       data.dsize = sizeof(uint32_t);
+       if (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_BANNED)) {
+               DEBUG(DEBUG_ERR,("Node %u is not banned.\n", options.pnn));
+               return -1;
+       }
 
-       ret = ctdb_send_message(ctdb, options.pnn, CTDB_SRVID_UNBAN_NODE, data);
+       bantime.pnn  = options.pnn;
+       bantime.time = 0;
+
+       ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, &bantime);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR,("Failed to to unban node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR,("Unbanning node %d failed.\n", bantime.pnn));
                return -1;
-       }
-       
-       /* wait until we are in a new generation */
-       while (1) {
-               next_generation = get_generation(ctdb);
-               if (next_generation != generation) {
-                       return 0;
-               }
-               sleep(1);
+       }       
+
+       ret = control_ipreallocate(ctdb, argc, argv);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+               return ret;
        }
 
        return 0;
 }
 
 
+/*
+  show ban information for a node
+ */
+static int control_showban(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       struct ctdb_node_map *nodemap=NULL;
+       struct ctdb_ban_time *bantime;
+
+       /* verify the node exists */
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               return ret;
+       }
+
+       ret = ctdb_ctrl_get_ban(ctdb, TIMELIMIT(), options.pnn, ctdb, &bantime);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Showing ban info for node %d failed.\n", options.pnn));
+               return -1;
+       }       
+
+       if (bantime->time == 0) {
+               printf("Node %u is not banned\n", bantime->pnn);
+       } else {
+               printf("Node %u is banned banned for %d seconds\n", bantime->pnn, bantime->time);
+       }
+
+       return 0;
+}
+
 /*
   shutdown a daemon
  */
@@ -1492,7 +2151,7 @@ static int control_recover(struct ctdb_context *ctdb, int argc, const char **arg
        /* record the current generation number */
        generation = get_generation(ctdb);
 
-       ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.pnn);
+       ret = ctdb_ctrl_freeze_priority(ctdb, TIMELIMIT(), options.pnn, 1);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to freeze node\n"));
                return ret;
@@ -1558,12 +2217,14 @@ static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const ch
                printf("RECMASTER: %s\n", (capabilities&CTDB_CAP_RECMASTER)?"YES":"NO");
                printf("LMASTER: %s\n", (capabilities&CTDB_CAP_LMASTER)?"YES":"NO");
                printf("LVS: %s\n", (capabilities&CTDB_CAP_LVS)?"YES":"NO");
+               printf("NATGW: %s\n", (capabilities&CTDB_CAP_NATGW)?"YES":"NO");
        } else {
-               printf(":RECMASTER:LMASTER:LVS:\n");
-               printf(":%d:%d:%d:\n",
+               printf(":RECMASTER:LMASTER:LVS:NATGW:\n");
+               printf(":%d:%d:%d:%d:\n",
                        !!(capabilities&CTDB_CAP_RECMASTER),
                        !!(capabilities&CTDB_CAP_LMASTER),
-                       !!(capabilities&CTDB_CAP_LVS));
+                       !!(capabilities&CTDB_CAP_LVS),
+                       !!(capabilities&CTDB_CAP_NATGW));
        }
        return 0;
 }
@@ -1697,12 +2358,16 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
                        }
                }
 
-               printf("Node %d is LVS master\n", i);
+               if (options.machinereadable){
+                       printf("%d\n", i);
+               } else {
+                       printf("Node %d is LVS master\n", i);
+               }
                return 0;
        }
 
        printf("There is no LVS master\n");
-       return 0;
+       return -1;
 }
 
 /*
@@ -1782,6 +2447,100 @@ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
 }
 
 
+static void log_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+                            TDB_DATA data, void *private_data)
+{
+       DEBUG(DEBUG_ERR,("Log data received\n"));
+       if (data.dsize > 0) {
+               printf("%s", data.dptr);
+       }
+
+       exit(0);
+}
+
+/*
+  display a list of log messages from the in memory ringbuffer
+ */
+static int control_getlog(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       int32_t res;
+       struct ctdb_get_log_addr log_addr;
+       TDB_DATA data;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+       char *errmsg;
+       struct timeval tv;
+
+       if (argc != 1) {
+               DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       log_addr.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+       log_addr.srvid = getpid();
+       if (isalpha(argv[0][0]) || argv[0][0] == '-') { 
+               log_addr.level = get_debug_by_desc(argv[0]);
+       } else {
+               log_addr.level = strtol(argv[0], NULL, 0);
+       }
+
+
+       data.dptr = (unsigned char *)&log_addr;
+       data.dsize = sizeof(log_addr);
+
+       DEBUG(DEBUG_ERR, ("Pulling logs from node %u\n", options.pnn));
+
+       ctdb_set_message_handler(ctdb, log_addr.srvid, log_handler, NULL);
+       sleep(1);
+
+       DEBUG(DEBUG_ERR,("Listen for response on %d\n", (int)log_addr.srvid));
+
+       ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_GET_LOG,
+                          0, data, tmp_ctx, NULL, &res, NULL, &errmsg);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,("Failed to get logs - %s\n", errmsg));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+
+       tv = timeval_current();
+       /* this loop will terminate when we have received the reply */
+       while (timeval_elapsed(&tv) < 3.0) {    
+               event_loop_once(ctdb->ev);
+       }
+
+       DEBUG(DEBUG_INFO,("Timed out waiting for log data.\n"));
+
+       talloc_free(tmp_ctx);
+       return 0;
+}
+
+/*
+  clear the in memory log area
+ */
+static int control_clearlog(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       int32_t res;
+       char *errmsg;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+       ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_CLEAR_LOG,
+                          0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,("Failed to clear logs\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
+       return 0;
+}
+
+
+
 /*
   display a list of the databases on a remote ctdb
  */
@@ -1934,92 +2693,204 @@ static int control_listvars(struct ctdb_context *ctdb, int argc, const char **ar
        return 0;
 }
 
-static struct {
-       int32_t level;
-       const char *description;
-} debug_levels[] = {
-       {DEBUG_EMERG,   "EMERG"},
-       {DEBUG_ALERT,   "ALERT"},
-       {DEBUG_CRIT,    "CRIT"},
-       {DEBUG_ERR,     "ERR"},
-       {DEBUG_WARNING, "WARNING"},
-       {DEBUG_NOTICE,  "NOTICE"},
-       {DEBUG_INFO,    "INFO"},
-       {DEBUG_DEBUG,   "DEBUG"}
-};
+/*
+  display debug level on a node
+ */
+static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       int32_t level;
+
+       ret = ctdb_ctrl_get_debuglevel(ctdb, options.pnn, &level);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get debuglevel response from node %u\n", options.pnn));
+               return ret;
+       } else {
+               if (options.machinereadable){
+                       printf(":Name:Level:\n");
+                       printf(":%s:%d:\n",get_debug_by_level(level),level);
+               } else {
+                       printf("Node %u is at debug level %s (%d)\n", options.pnn, get_debug_by_level(level), level);
+               }
+       }
+       return 0;
+}
 
-static const char *get_debug_by_level(int32_t level)
+/*
+  display reclock file of a node
+ */
+static int control_getreclock(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int i;
+       int ret;
+       const char *reclock;
 
-       for (i=0;i<ARRAY_SIZE(debug_levels);i++) {
-               if (debug_levels[i].level == level) {
-                       return debug_levels[i].description;
+       ret = ctdb_ctrl_getreclock(ctdb, TIMELIMIT(), options.pnn, ctdb, &reclock);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get reclock file from node %u\n", options.pnn));
+               return ret;
+       } else {
+               if (options.machinereadable){
+                       if (reclock != NULL) {
+                               printf("%s", reclock);
+                       }
+               } else {
+                       if (reclock == NULL) {
+                               printf("No reclock file used.\n");
+                       } else {
+                               printf("Reclock file:%s\n", reclock);
+                       }
                }
        }
-       return "Unknown";
+       return 0;
 }
 
-static int32_t get_debug_by_desc(const char *desc)
+/*
+  set the reclock file of a node
+ */
+static int control_setreclock(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int i;
+       int ret;
+       const char *reclock;
+
+       if (argc == 0) {
+               reclock = NULL;
+       } else if (argc == 1) {
+               reclock = argv[0];
+       } else {
+               usage();
+       }
+
+       ret = ctdb_ctrl_setreclock(ctdb, TIMELIMIT(), options.pnn, reclock);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get reclock file from node %u\n", options.pnn));
+               return ret;
+       }
+       return 0;
+}
+
+/*
+  set the natgw state on/off
+ */
+static int control_setnatgwstate(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       uint32_t natgwstate;
+
+       if (argc == 0) {
+               usage();
+       }
+
+       if (!strcmp(argv[0], "on")) {
+               natgwstate = 1;
+       } else if (!strcmp(argv[0], "off")) {
+               natgwstate = 0;
+       } else {
+               usage();
+       }
+
+       ret = ctdb_ctrl_setnatgwstate(ctdb, TIMELIMIT(), options.pnn, natgwstate);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to set the natgw state for node %u\n", options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+  set the lmaster role on/off
+ */
+static int control_setlmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       uint32_t lmasterrole;
+
+       if (argc == 0) {
+               usage();
+       }
 
-       for (i=0;i<ARRAY_SIZE(debug_levels);i++) {
-               if (!strcmp(debug_levels[i].description, desc)) {
-                       return debug_levels[i].level;
-               }
+       if (!strcmp(argv[0], "on")) {
+               lmasterrole = 1;
+       } else if (!strcmp(argv[0], "off")) {
+               lmasterrole = 0;
+       } else {
+               usage();
        }
 
-       fprintf(stderr, "Invalid debug level '%s'\nMust be one of\n", desc);
-       for (i=0;i<ARRAY_SIZE(debug_levels);i++) {
-               fprintf(stderr, "    %s\n", debug_levels[i].description);
+       ret = ctdb_ctrl_setlmasterrole(ctdb, TIMELIMIT(), options.pnn, lmasterrole);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to set the lmaster role for node %u\n", options.pnn));
+               return ret;
        }
 
-       exit(10);
+       return 0;
 }
 
 /*
-  display debug level on a node
+  set the recmaster role on/off
  */
-static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_setrecmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
-       int32_t level;
+       uint32_t recmasterrole;
 
-       ret = ctdb_ctrl_get_debuglevel(ctdb, options.pnn, &level);
+       if (argc == 0) {
+               usage();
+       }
+
+       if (!strcmp(argv[0], "on")) {
+               recmasterrole = 1;
+       } else if (!strcmp(argv[0], "off")) {
+               recmasterrole = 0;
+       } else {
+               usage();
+       }
+
+       ret = ctdb_ctrl_setrecmasterrole(ctdb, TIMELIMIT(), options.pnn, recmasterrole);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get debuglevel response from node %u\n", options.pnn));
+               DEBUG(DEBUG_ERR, ("Unable to set the recmaster role for node %u\n", options.pnn));
                return ret;
-       } else {
-               if (options.machinereadable){
-                       printf(":Name:Level:\n");
-                       printf(":%s:%d:\n",get_debug_by_level(level),level);
-               } else {
-                       printf("Node %u is at debug level %s (%d)\n", options.pnn, get_debug_by_level(level), level);
-               }
        }
+
        return 0;
 }
 
-
 /*
   set debug level on a node or all nodes
  */
 static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int ret;
+       int i, ret;
        int32_t level;
 
-       if (argc < 1) {
-               usage();
+       if (argc == 0) {
+               printf("You must specify the debug level. Valid levels are:\n");
+               for (i=0; debug_levels[i].description != NULL; i++) {
+                       printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
+               }
+
+               return 0;
        }
 
-       if (isalpha(argv[0][0])) { 
+       if (isalpha(argv[0][0]) || argv[0][0] == '-') { 
                level = get_debug_by_desc(argv[0]);
        } else {
                level = strtol(argv[0], NULL, 0);
        }
 
+       for (i=0; debug_levels[i].description != NULL; i++) {
+               if (level == debug_levels[i].level) {
+                       break;
+               }
+       }
+       if (debug_levels[i].description == NULL) {
+               printf("Invalid debug level, must be one of\n");
+               for (i=0; debug_levels[i].description != NULL; i++) {
+                       printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
+               }
+               return -1;
+       }
+
        ret = ctdb_ctrl_set_debuglevel(ctdb, options.pnn, level);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to set debug level on node %u\n", options.pnn));
@@ -2034,8 +2905,16 @@ static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **ar
 static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
+       uint32_t priority;
+       
+       if (argc == 1) {
+               priority = strtol(argv[0], NULL, 0);
+       } else {
+               priority = 0;
+       }
+       DEBUG(DEBUG_ERR,("Freeze by priority %u\n", priority));
 
-       ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.pnn);
+       ret = ctdb_ctrl_freeze_priority(ctdb, TIMELIMIT(), options.pnn, priority);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to freeze node %u\n", options.pnn));
        }               
@@ -2048,8 +2927,16 @@ static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv
 static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int ret;
+       uint32_t priority;
+       
+       if (argc == 1) {
+               priority = strtol(argv[0], NULL, 0);
+       } else {
+               priority = 0;
+       }
+       DEBUG(DEBUG_ERR,("Thaw by priority %u\n", priority));
 
-       ret = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), options.pnn);
+       ret = ctdb_ctrl_thaw_priority(ctdb, TIMELIMIT(), options.pnn, priority);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to thaw node %u\n", options.pnn));
        }               
@@ -2079,6 +2966,55 @@ static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv
        return 0;
 }
 
+/*
+  set db priority
+ */
+static int control_setdbprio(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       struct ctdb_db_priority db_prio;
+       int ret;
+
+       if (argc < 2) {
+               usage();
+       }
+
+       db_prio.db_id    = strtoul(argv[0], NULL, 0);
+       db_prio.priority = strtoul(argv[1], NULL, 0);
+
+       ret = ctdb_ctrl_set_db_priority(ctdb, TIMELIMIT(), options.pnn, &db_prio);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Unable to set db prio\n"));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  get db priority
+ */
+static int control_getdbprio(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t db_id, priority;
+       int ret;
+
+       if (argc < 1) {
+               usage();
+       }
+
+       db_id = strtoul(argv[0], NULL, 0);
+
+       ret = ctdb_ctrl_get_db_priority(ctdb, TIMELIMIT(), options.pnn, db_id, &priority);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Unable to get db prio\n"));
+               return -1;
+       }
+
+       DEBUG(DEBUG_ERR,("Priority:%u\n", priority));
+
+       return 0;
+}
+
 /*
   run an eventscript on a node
  */
@@ -2166,7 +3102,8 @@ static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **ar
        struct db_file_header dbhdr;
        struct ctdb_db_context *ctdb_db;
        struct backup_data *bd;
-       int fh;
+       int fh = -1;
+       int status = -1;
 
        if (argc != 2) {
                DEBUG(DEBUG_ERR,("Invalid arguments\n"));
@@ -2199,6 +3136,7 @@ static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **ar
        ctdb_db = ctdb_attach(ctdb, argv[0], dbmap->dbs[i].persistent, 0);
        if (ctdb_db == NULL) {
                DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", argv[0]));
+               talloc_free(tmp_ctx);
                return -1;
        }
 
@@ -2251,16 +3189,30 @@ static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **ar
        dbhdr.size = bd->len;
        if (strlen(argv[0]) >= MAX_DB_NAME) {
                DEBUG(DEBUG_ERR,("Too long dbname\n"));
-               talloc_free(tmp_ctx);
-               return -1;
+               goto done;
        }
        strncpy(discard_const(dbhdr.name), argv[0], MAX_DB_NAME);
-       write(fh, &dbhdr, sizeof(dbhdr));
-       write(fh, bd->records, bd->len);
+       ret = write(fh, &dbhdr, sizeof(dbhdr));
+       if (ret == -1) {
+               DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
+               goto done;
+       }
+       ret = write(fh, bd->records, bd->len);
+       if (ret == -1) {
+               DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
+               goto done;
+       }
 
-       close(fh);
+       status = 0;
+done:
+       if (fh != -1) {
+               ret = close(fh);
+               if (ret == -1) {
+                       DEBUG(DEBUG_ERR,("close failed: %s\n", strerror(errno)));
+               }
+       }
        talloc_free(tmp_ctx);
-       return 0;
+       return status;
 }
 
 /*
@@ -2276,7 +3228,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        struct ctdb_db_context *ctdb_db;
        struct ctdb_node_map *nodemap=NULL;
        struct ctdb_vnn_map *vnnmap=NULL;
-       int fh;
+       int i, fh;
        struct ctdb_control_wipe_database w;
        uint32_t *nodes;
        uint32_t generation;
@@ -2343,15 +3295,18 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
 
        /* freeze all nodes */
        nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
-       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
-                                       nodes, TIMELIMIT(),
+       for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+               if (ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+                                       nodes, i,
+                                       TIMELIMIT(),
                                        false, tdb_null,
                                        NULL, NULL,
                                        NULL) != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
-               ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
-               talloc_free(tmp_ctx);
-               return -1;
+                       DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
+                       ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+                       talloc_free(tmp_ctx);
+                       return -1;
+               }
        }
 
        generation = vnnmap->generation;
@@ -2361,7 +3316,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        /* start a cluster wide transaction */
        nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
        if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
-                                       nodes,
+                                       nodes, 0,
                                        TIMELIMIT(), false, data,
                                        NULL, NULL,
                                        NULL) != 0) {
@@ -2379,7 +3334,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        /* wipe all the remote databases. */
        nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
        if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
-                                       nodes,
+                                       nodes, 0,
                                        TIMELIMIT(), false, data,
                                        NULL, NULL,
                                        NULL) != 0) {
@@ -2392,7 +3347,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        /* push the database */
        nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
        if (ctdb_client_async_control(ctdb, CTDB_CONTROL_PUSH_DB,
-                                       nodes,
+                                       nodes, 0,
                                        TIMELIMIT(), false, outdata,
                                        NULL, NULL,
                                        NULL) != 0) {
@@ -2407,7 +3362,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
 
        /* commit all the changes */
        if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
-                                       nodes,
+                                       nodes, 0,
                                        TIMELIMIT(), false, data,
                                        NULL, NULL,
                                        NULL) != 0) {
@@ -2421,7 +3376,8 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        /* thaw all nodes */
        nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
        if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW,
-                                       nodes, TIMELIMIT(),
+                                       nodes, 0,
+                                       TIMELIMIT(),
                                        false, tdb_null,
                                        NULL, NULL,
                                        NULL) != 0) {
@@ -2436,6 +3392,168 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a
        return 0;
 }
 
+/*
+ * wipe a database from a file
+ */
+static int control_wipedb(struct ctdb_context *ctdb, int argc,
+                         const char **argv)
+{
+       int ret;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+       TDB_DATA data;
+       struct ctdb_db_context *ctdb_db;
+       struct ctdb_node_map *nodemap = NULL;
+       struct ctdb_vnn_map *vnnmap = NULL;
+       int i;
+       struct ctdb_control_wipe_database w;
+       uint32_t *nodes;
+       uint32_t generation;
+       struct ctdb_dbid_map *dbmap = NULL;
+
+       if (argc != 1) {
+               DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+               return -1;
+       }
+
+       ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+                                &dbmap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n",
+                                 options.pnn));
+               return ret;
+       }
+
+       for(i=0;i<dbmap->num;i++){
+               const char *name;
+
+               ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
+                                   dbmap->dbs[i].dbid, tmp_ctx, &name);
+               if(!strcmp(argv[0], name)){
+                       talloc_free(discard_const(name));
+                       break;
+               }
+               talloc_free(discard_const(name));
+       }
+       if (i == dbmap->num) {
+               DEBUG(DEBUG_ERR, ("No database with name '%s' found\n",
+                                 argv[0]));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       ctdb_db = ctdb_attach(ctdb, argv[0], dbmap->dbs[i].persistent, 0);
+       if (ctdb_db == NULL) {
+               DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n",
+                                 argv[0]));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb,
+                                  &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n",
+                                 options.pnn));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+       ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+                                 &vnnmap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n",
+                                 options.pnn));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+       /* freeze all nodes */
+       nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+       for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+               ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+                                               nodes, i,
+                                               TIMELIMIT(),
+                                               false, tdb_null,
+                                               NULL, NULL,
+                                               NULL);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
+                       ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn,
+                                            CTDB_RECOVERY_ACTIVE);
+                       talloc_free(tmp_ctx);
+                       return -1;
+               }
+       }
+
+       generation = vnnmap->generation;
+       data.dptr = (void *)&generation;
+       data.dsize = sizeof(generation);
+
+       /* start a cluster wide transaction */
+       nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+       ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
+                                       nodes, 0,
+                                       TIMELIMIT(), false, data,
+                                       NULL, NULL,
+                                       NULL);
+       if (ret!= 0) {
+               DEBUG(DEBUG_ERR, ("Unable to start cluster wide "
+                                 "transactions.\n"));
+               return -1;
+       }
+
+       w.db_id = ctdb_db->db_id;
+       w.transaction_id = generation;
+
+       data.dptr = (void *)&w;
+       data.dsize = sizeof(w);
+
+       /* wipe all the remote databases. */
+       nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
+                                       nodes, 0,
+                                       TIMELIMIT(), false, data,
+                                       NULL, NULL,
+                                       NULL) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to wipe database.\n"));
+               ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       data.dptr = (void *)&generation;
+       data.dsize = sizeof(generation);
+
+       /* commit all the changes */
+       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
+                                       nodes, 0,
+                                       TIMELIMIT(), false, data,
+                                       NULL, NULL,
+                                       NULL) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to commit databases.\n"));
+               ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       /* thaw all nodes */
+       nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW,
+                                       nodes, 0,
+                                       TIMELIMIT(),
+                                       false, tdb_null,
+                                       NULL, NULL,
+                                       NULL) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n"));
+               ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
+       return 0;
+}
+
 /*
  * set flags of a node in the nodemap
  */
@@ -2553,20 +3671,59 @@ static int control_rddumpmemory(struct ctdb_context *ctdb, int argc, const char
 
 /*
   list all nodes in the cluster
+  if the daemon is running, we read the data from the daemon.
+  if the daemon is not running we parse the nodes file directly
  */
 static int control_listnodes(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int i, ret;
        struct ctdb_node_map *nodemap=NULL;
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
-               return ret;
-       }
+       if (ctdb != NULL) {
+               ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+                       return ret;
+               }
 
-       for(i=0;i<nodemap->num;i++){
-               printf("%s\n", ctdb_addr_to_str(&nodemap->nodes[i].addr));
+               for(i=0;i<nodemap->num;i++){
+                       if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+                               continue;
+                       }
+                       if (options.machinereadable){
+                               printf(":%d:%s:\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr));
+                       } else {
+                               printf("%s\n", ctdb_addr_to_str(&nodemap->nodes[i].addr));
+                       }
+               }
+       } else {
+               TALLOC_CTX *mem_ctx = talloc_new(NULL);
+               struct pnn_node *pnn_nodes;
+               struct pnn_node *pnn_node;
+       
+               pnn_nodes = read_nodes_file(mem_ctx);
+               if (pnn_nodes == NULL) {
+                       DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+                       talloc_free(mem_ctx);
+                       return -1;
+               }
+
+               for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
+                       ctdb_sock_addr addr;
+
+                       if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
+                               DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
+                               talloc_free(mem_ctx);
+                               return -1;
+                       }
+
+                       if (options.machinereadable){
+                               printf(":%d:%s:\n", pnn_node->pnn, pnn_node->addr);
+                       } else {
+                               printf("%s\n", pnn_node->addr);
+                       }
+               }
+               talloc_free(mem_ctx);
        }
 
        return 0;
@@ -2624,68 +3781,87 @@ static const struct {
        const char *name;
        int (*fn)(struct ctdb_context *, int, const char **);
        bool auto_all;
+       bool without_daemon; /* can be run without daemon running ? */
        const char *msg;
        const char *args;
 } ctdb_commands[] = {
 #ifdef CTDB_VERS
-       { "version",         control_version,           true,  "show version of ctdb" },
+       { "version",         control_version,           true,   false,  "show version of ctdb" },
 #endif
-       { "status",          control_status,            true,  "show node status" },
-       { "uptime",          control_uptime,            true,  "show node uptime" },
-       { "ping",            control_ping,              true,  "ping all nodes" },
-       { "getvar",          control_getvar,            true,  "get a tunable variable",               "<name>"},
-       { "setvar",          control_setvar,            true,  "set a tunable variable",               "<name> <value>"},
-       { "listvars",        control_listvars,          true,  "list tunable variables"},
-       { "statistics",      control_statistics,        false, "show statistics" },
-       { "statisticsreset", control_statistics_reset,  true,  "reset statistics"},
-       { "ip",              control_ip,                false,  "show which public ip's that ctdb manages" },
-       { "process-exists",  control_process_exists,    true,  "check if a process exists on a node",  "<pid>"},
-       { "getdbmap",        control_getdbmap,          true,  "show the database map" },
-       { "catdb",           control_catdb,             true,  "dump a database" ,                     "<dbname>"},
-       { "getmonmode",      control_getmonmode,        true,  "show monitoring mode" },
-       { "getcapabilities", control_getcapabilities,   true,  "show node capabilities" },
-       { "pnn",             control_pnn,               true,  "show the pnn of the currnet node" },
-       { "lvs",             control_lvs,               true,  "show lvs configuration" },
-       { "lvsmaster",       control_lvsmaster,         true,  "show which node is the lvs master" },
-       { "disablemonitor",      control_disable_monmode,        true,  "set monitoring mode to DISABLE" },
-       { "enablemonitor",      control_enable_monmode,        true,  "set monitoring mode to ACTIVE" },
-       { "setdebug",        control_setdebug,          true,  "set debug level",                      "<EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG>" },
-       { "getdebug",        control_getdebug,          true,  "get debug level" },
-       { "attach",          control_attach,            true,  "attach to a database",                 "<dbname>" },
-       { "dumpmemory",      control_dumpmemory,        true,  "dump memory map to stdout" },
-       { "rddumpmemory",    control_rddumpmemory,      true,  "dump memory map from the recovery daemon to stdout" },
-       { "getpid",          control_getpid,            true,  "get ctdbd process ID" },
-       { "disable",         control_disable,           true,  "disable a nodes public IP" },
-       { "enable",          control_enable,            true,  "enable a nodes public IP" },
-       { "ban",             control_ban,               true,  "ban a node from the cluster",          "<bantime|0>"},
-       { "unban",           control_unban,             true,  "unban a node from the cluster" },
-       { "shutdown",        control_shutdown,          true,  "shutdown ctdbd" },
-       { "recover",         control_recover,           true,  "force recovery" },
-       { "freeze",          control_freeze,            true,  "freeze all databases" },
-       { "thaw",            control_thaw,              true,  "thaw all databases" },
-       { "isnotrecmaster",  control_isnotrecmaster,    false,  "check if the local node is recmaster or not" },
-       { "killtcp",         kill_tcp,                  false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
-       { "gratiousarp",     control_gratious_arp,      false, "send a gratious arp", "<ip> <interface>" },
-       { "tickle",          tickle_tcp,                false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
-       { "gettickles",      control_get_tickles,       false, "get the list of tickles registered for this ip", "<ip>" },
-
-       { "regsrvid",        regsrvid,                  false, "register a server id", "<pnn> <type> <id>" },
-       { "unregsrvid",      unregsrvid,                false, "unregister a server id", "<pnn> <type> <id>" },
-       { "chksrvid",        chksrvid,                  false, "check if a server id exists", "<pnn> <type> <id>" },
-       { "getsrvids",       getsrvids,                 false, "get a list of all server ids"},
-       { "vacuum",          ctdb_vacuum,               false, "vacuum the databases of empty records", "[max_records]"},
-       { "repack",          ctdb_repack,               false, "repack all databases", "[max_freelist]"},
-       { "listnodes",       control_listnodes,         false, "list all nodes in the cluster"},
-       { "reloadnodes",     control_reload_nodes_file,         false, "reload the nodes file and restart the transport on all nodes"},
-       { "moveip",          control_moveip,            false, "move/failover an ip address to another node", "<ip> <node>"},
-       { "addip",           control_addip,             true, "add a ip address to a node", "<ip/mask> <iface>"},
-       { "delip",           control_delip,             false, "delete an ip address from a node", "<ip>"},
-       { "eventscript",     control_eventscript,       true, "run the eventscript with the given parameters on a node", "<arguments>"},
-       { "backupdb",        control_backupdb,          false, "backup the database into a file.", "<database> <file>"},
-       { "restoredb",        control_restoredb,          false, "restore the database from a file.", "<file>"},
-       { "recmaster",        control_recmaster,          false, "show the pnn for the recovery master."},
-       { "setflags",        control_setflags,            false, "set flags for a node in the nodemap.", "<node> <flags>"},
-       { "scriptstatus",        control_scriptstatus,    false, "show the status of the monitoring scripts"},
+       { "status",          control_status,            true,   false,  "show node status" },
+       { "uptime",          control_uptime,            true,   false,  "show node uptime" },
+       { "ping",            control_ping,              true,   false,  "ping all nodes" },
+       { "getvar",          control_getvar,            true,   false,  "get a tunable variable",               "<name>"},
+       { "setvar",          control_setvar,            true,   false,  "set a tunable variable",               "<name> <value>"},
+       { "listvars",        control_listvars,          true,   false,  "list tunable variables"},
+       { "statistics",      control_statistics,        false,  false, "show statistics" },
+       { "statisticsreset", control_statistics_reset,  true,   false,  "reset statistics"},
+       { "ip",              control_ip,                false,  false,  "show which public ip's that ctdb manages" },
+       { "process-exists",  control_process_exists,    true,   false,  "check if a process exists on a node",  "<pid>"},
+       { "getdbmap",        control_getdbmap,          true,   false,  "show the database map" },
+       { "catdb",           control_catdb,             true,   false,  "dump a database" ,                     "<dbname>"},
+       { "getmonmode",      control_getmonmode,        true,   false,  "show monitoring mode" },
+       { "getcapabilities", control_getcapabilities,   true,   false,  "show node capabilities" },
+       { "pnn",             control_pnn,               true,   false,  "show the pnn of the currnet node" },
+       { "lvs",             control_lvs,               true,   false,  "show lvs configuration" },
+       { "lvsmaster",       control_lvsmaster,         true,   false,  "show which node is the lvs master" },
+       { "disablemonitor",      control_disable_monmode,true,  false,  "set monitoring mode to DISABLE" },
+       { "enablemonitor",      control_enable_monmode, true,   false,  "set monitoring mode to ACTIVE" },
+       { "setdebug",        control_setdebug,          true,   false,  "set debug level",                      "<EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG>" },
+       { "getdebug",        control_getdebug,          true,   false,  "get debug level" },
+       { "getlog",          control_getlog,            true,   false,  "get the log data from the in memory ringbuffer", "<level>" },
+       { "clearlog",          control_clearlog,        true,   false,  "clear the log data from the in memory ringbuffer" },
+       { "attach",          control_attach,            true,   false,  "attach to a database",                 "<dbname>" },
+       { "dumpmemory",      control_dumpmemory,        true,   false,  "dump memory map to stdout" },
+       { "rddumpmemory",    control_rddumpmemory,      true,   false,  "dump memory map from the recovery daemon to stdout" },
+       { "getpid",          control_getpid,            true,   false,  "get ctdbd process ID" },
+       { "disable",         control_disable,           true,   false,  "disable a nodes public IP" },
+       { "enable",          control_enable,            true,   false,  "enable a nodes public IP" },
+       { "stop",            control_stop,              true,   false,  "stop a node" },
+       { "continue",        control_continue,          true,   false,  "re-start a stopped node" },
+       { "ban",             control_ban,               true,   false,  "ban a node from the cluster",          "<bantime|0>"},
+       { "unban",           control_unban,             true,   false,  "unban a node" },
+       { "showban",         control_showban,           true,   false,  "show ban information"},
+       { "shutdown",        control_shutdown,          true,   false,  "shutdown ctdbd" },
+       { "recover",         control_recover,           true,   false,  "force recovery" },
+       { "ipreallocate",    control_ipreallocate,      true,   false,  "force the recovery daemon to perform a ip reallocation procedure" },
+       { "freeze",          control_freeze,            true,   false,  "freeze databases", "[priority:1-3]" },
+       { "thaw",            control_thaw,              true,   false,  "thaw databases", "[priority:1-3]" },
+       { "isnotrecmaster",  control_isnotrecmaster,    false,  false,  "check if the local node is recmaster or not" },
+       { "killtcp",         kill_tcp,                  false,  false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
+       { "gratiousarp",     control_gratious_arp,      false,  false, "send a gratious arp", "<ip> <interface>" },
+       { "tickle",          tickle_tcp,                false,  false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
+       { "gettickles",      control_get_tickles,       false,  false, "get the list of tickles registered for this ip", "<ip>" },
+
+       { "regsrvid",        regsrvid,                  false,  false, "register a server id", "<pnn> <type> <id>" },
+       { "unregsrvid",      unregsrvid,                false,  false, "unregister a server id", "<pnn> <type> <id>" },
+       { "chksrvid",        chksrvid,                  false,  false, "check if a server id exists", "<pnn> <type> <id>" },
+       { "getsrvids",       getsrvids,                 false,  false, "get a list of all server ids"},
+       { "vacuum",          ctdb_vacuum,               false,  false, "vacuum the databases of empty records", "[max_records]"},
+       { "repack",          ctdb_repack,               false,  false, "repack all databases", "[max_freelist]"},
+       { "listnodes",       control_listnodes,         false,  true, "list all nodes in the cluster"},
+       { "reloadnodes",     control_reload_nodes_file, false,  false, "reload the nodes file and restart the transport on all nodes"},
+       { "moveip",          control_moveip,            false,  false, "move/failover an ip address to another node", "<ip> <node>"},
+       { "addip",           control_addip,             true,   false, "add a ip address to a node", "<ip/mask> <iface>"},
+       { "delip",           control_delip,             false,  false, "delete an ip address from a node", "<ip>"},
+       { "eventscript",     control_eventscript,       true,   false, "run the eventscript with the given parameters on a node", "<arguments>"},
+       { "backupdb",        control_backupdb,          false,  false, "backup the database into a file.", "<database> <file>"},
+       { "restoredb",        control_restoredb,        false,  false, "restore the database from a file.", "<file>"},
+       { "wipedb",           control_wipedb,        false,     false, "wipe the contents of a database.", "<dbname>"},
+       { "recmaster",        control_recmaster,        false,  false, "show the pnn for the recovery master."},
+       { "setflags",        control_setflags,          false,  false, "set flags for a node in the nodemap.", "<node> <flags>"},
+       { "scriptstatus",    control_scriptstatus,  false,      false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
+       { "enablescript",     control_enablescript,  false,     false, "enable an eventscript", "<script>"},
+       { "disablescript",    control_disablescript,  false,    false, "disable an eventscript", "<script>"},
+       { "natgwlist",        control_natgwlist,        false,  false, "show the nodes belonging to this natgw configuration"},
+       { "xpnn",             control_xpnn,             true,   true,  "find the pnn of the local node without talking to the daemon (unreliable)" },
+       { "getreclock",       control_getreclock,       false,  false, "Show the reclock file of a node"},
+       { "setreclock",       control_setreclock,       false,  false, "Set/clear the reclock file of a node", "[filename]"},
+       { "setnatgwstate",    control_setnatgwstate,    false,  false, "Set NATGW state to on/off", "{on|off}"},
+       { "setlmasterrole",   control_setlmasterrole,   false,  false, "Set LMASTER role to on/off", "{on|off}"},
+       { "setrecmasterrole", control_setrecmasterrole, false,  false, "Set RECMASTER role to on/off", "{on|off}"},
+       { "setdbprio",        control_setdbprio,        false,  false, "Set DB priority", "<dbid> <prio:1-3>"},
+       { "getdbprio",        control_getdbprio,        false,  false, "Get DB priority", "<dbid>"},
 };
 
 /*
@@ -2775,12 +3951,14 @@ int main(int argc, const char *argv[])
                ctdb_timeout = getenv("CTDB_TIMEOUT");
                if (ctdb_timeout != NULL) {
                        options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
+               } else {
+                       /* default timeout is 120 seconds */
+                       options.maxruntime = 120;
                }
        }
-       if (options.maxruntime != 0) {
-               signal(SIGALRM, ctdb_alarm);
-               alarm(options.maxruntime);
-       }
+
+       signal(SIGALRM, ctdb_alarm);
+       alarm(options.maxruntime);
 
        /* setup the node number to contact */
        if (nodestring != NULL) {
@@ -2795,27 +3973,34 @@ int main(int argc, const char *argv[])
 
        ev = event_context_init(NULL);
 
-       /* initialise ctdb */
-       ctdb = ctdb_cmdline_client(ev);
-       if (ctdb == NULL) {
-               DEBUG(DEBUG_ERR, ("Failed to init ctdb\n"));
-               exit(1);
-       }
-
-       /* verify the node exists */
-       verify_node(ctdb);
-
        for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
                if (strcmp(control, ctdb_commands[i].name) == 0) {
                        int j;
 
-                       if (options.pnn == CTDB_CURRENT_NODE) {
-                               int pnn;
-                               pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);         
-                               if (pnn == -1) {
-                                       return -1;
+                       if (ctdb_commands[i].without_daemon == true) {
+                               close(2);
+                       }
+
+                       /* initialise ctdb */
+                       ctdb = ctdb_cmdline_client(ev);
+
+                       if (ctdb_commands[i].without_daemon == false) {
+                               if (ctdb == NULL) {
+                                       DEBUG(DEBUG_ERR, ("Failed to init ctdb\n"));
+                                       exit(1);
+                               }
+
+                               /* verify the node exists */
+                               verify_node(ctdb);
+
+                               if (options.pnn == CTDB_CURRENT_NODE) {
+                                       int pnn;
+                                       pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);         
+                                       if (pnn == -1) {
+                                               return -1;
+                                       }
+                                       options.pnn = pnn;
                                }
-                               options.pnn = pnn;
                        }
 
                        if (ctdb_commands[i].auto_all &&