libndr: Avoid assigning duplicate versions to symbols
[amitay/samba.git] / ctdb / tools / ctdb.c
index 4e767ae0fd376f3cac26de25797205ce0b8134fb..e21d2d4b562c6ac96d317e562e274a8444ac2054 100644 (file)
@@ -22,6 +22,7 @@
 #include "system/filesys.h"
 #include "system/time.h"
 #include "system/wait.h"
+#include "system/dir.h"
 
 #include <ctype.h>
 #include <popt.h>
 #include <tevent.h>
 #include <tdb.h>
 
-#include "ctdb_version.h"
+#include "version.h"
 #include "lib/util/debug.h"
 #include "lib/util/samba_util.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/smb_strtox.h"
 
 #include "common/db_hash.h"
 #include "common/logging.h"
+#include "common/path.h"
 #include "protocol/protocol.h"
 #include "protocol/protocol_api.h"
-#include "common/system.h"
+#include "protocol/protocol_util.h"
+#include "common/system_socket.h"
 #include "client/client.h"
+#include "client/client_sync.h"
 
 #define TIMEOUT()      timeval_current_ofs(options.timelimit, 0)
 
@@ -46,7 +52,6 @@
 #define SRVID_CTDB_PUSHDB  (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
 
 static struct {
-       const char *socket;
        const char *debuglevelstr;
        int timelimit;
        int pnn;
@@ -88,7 +93,7 @@ static struct ctdb_node_and_flags *get_node_by_pnn(
                                        struct ctdb_node_map *nodemap,
                                        uint32_t pnn)
 {
-       int i;
+       unsigned int i;
 
        for (i=0; i<nodemap->num; i++) {
                if (nodemap->node[i].pnn == pnn) {
@@ -113,7 +118,7 @@ static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
                { NODE_FLAGS_INACTIVE,              "INACTIVE" },
        };
        char *flags_str = NULL;
-       int i;
+       size_t i;
 
        for (i=0; i<ARRAY_SIZE(flag_names); i++) {
                if (flags & flag_names[i].flag) {
@@ -212,7 +217,7 @@ static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
 {
        struct ctdb_node_map *nodemap;
        bool found;
-       int i;
+       unsigned int i;
 
        if (pnn == -1) {
                return false;
@@ -225,7 +230,7 @@ static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
 
        found = false;
        for (i=0; i<nodemap->num; i++) {
-               if (nodemap->node[i].pnn == pnn) {
+               if (nodemap->node[i].pnn == (uint32_t)pnn) {
                        found = true;
                        break;
                }
@@ -278,7 +283,7 @@ static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        struct ctdb_node_map *nodemap, *nodemap2;
        struct ctdb_node_and_flags *node;
-       int i;
+       unsigned int i;
 
        nodemap = get_nodemap(ctdb, false);
        if (nodemap == NULL) {
@@ -311,6 +316,7 @@ static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                goto done;
        } else {
                char *ns, *tok;
+               int error = 0;
 
                ns = talloc_strdup(mem_ctx, nodestring);
                if (ns == NULL) {
@@ -320,10 +326,13 @@ static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                tok = strtok(ns, ",");
                while (tok != NULL) {
                        uint32_t pnn;
-                       char *endptr;
 
-                       pnn = (uint32_t)strtoul(tok, &endptr, 0);
-                       if (pnn == 0 && tok == endptr) {
+                       pnn = (uint32_t)smb_strtoul(tok,
+                                                   NULL,
+                                                   0,
+                                                   &error,
+                                                   SMB_STR_STANDARD);
+                       if (error != 0) {
                                fprintf(stderr, "Invalid node %s\n", tok);
                                        return false;
                        }
@@ -378,8 +387,10 @@ static bool node_map_add(struct ctdb_node_map *nodemap,
        ctdb_sock_addr addr;
        uint32_t num;
        struct ctdb_node_and_flags *n;
+       int ret;
 
-       if (! parse_ip(nstr, NULL, 0, &addr)) {
+       ret = ctdb_sock_addr_from_string(nstr, &addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", nstr);
                return false;
        }
@@ -472,28 +483,16 @@ static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
 {
        struct ctdb_node_map *nodemap;
-       char *nodepath;
        const char *nodes_list = NULL;
 
-       if (pnn != CTDB_UNKNOWN_PNN) {
-               nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
-               if (nodepath != NULL) {
-                       nodes_list = getenv(nodepath);
-               }
+       const char *basedir = getenv("CTDB_BASE");
+       if (basedir == NULL) {
+               basedir = CTDB_ETCDIR;
        }
+       nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
        if (nodes_list == NULL) {
-               nodes_list = getenv("CTDB_NODES");
-       }
-       if (nodes_list == NULL) {
-               const char *basedir = getenv("CTDB_BASE");
-               if (basedir == NULL) {
-                       basedir = CTDB_ETCDIR;
-               }
-               nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
-               if (nodes_list == NULL) {
-                       fprintf(stderr, "Memory allocation error\n");
-                       return NULL;
-               }
+               fprintf(stderr, "Memory allocation error\n");
+               return NULL;
        }
 
        nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
@@ -513,7 +512,8 @@ static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
 {
        struct ctdb_dbid *db = NULL;
        const char *name;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        for (i=0; i<dbmap->num; i++) {
                ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
@@ -541,7 +541,8 @@ static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct ctdb_dbid *db = NULL;
        uint32_t id = 0;
        const char *name = NULL;
-       int ret, i;
+       unsigned int i;
+       int ret = 0;
 
        ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
                                  ctdb->pnn, TIMEOUT(), &dbmap);
@@ -550,7 +551,10 @@ static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        if (strncmp(db_arg, "0x", 2) == 0) {
-               id = strtoul(db_arg, NULL, 0);
+               id = smb_strtoul(db_arg, NULL, 0, &ret, SMB_STR_STANDARD);
+               if (ret != 0) {
+                       return false;
+               }
                for (i=0; i<dbmap->num; i++) {
                        if (id == dbmap->dbs[i].db_id) {
                                db = &dbmap->dbs[i];
@@ -593,7 +597,7 @@ static int h2i(char h)
                return h - 'a' + 10;
        }
        if (h >= 'A' && h <= 'F') {
-               return h - 'f' + 10;
+               return h - 'A' + 10;
        }
        return h - '0';
 }
@@ -601,7 +605,7 @@ static int h2i(char h)
 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
                       TDB_DATA *out)
 {
-       int i;
+       unsigned int i;
        TDB_DATA data;
 
        if (len & 0x01) {
@@ -632,6 +636,9 @@ static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
 
        if (strncmp(str, "0x", 2) == 0) {
                ret = hex_to_data(str+2, len-2, mem_ctx, &data);
+               if (ret != 0) {
+                       return ret;
+               }
        } else {
                data.dptr = talloc_memdup(mem_ctx, str, len);
                if (data.dptr == NULL) {
@@ -641,31 +648,48 @@ static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
        }
 
        *out = data;
-       return ret;
+       return 0;
 }
 
-static int run_helper(const char *command, const char *path, const char *arg1)
+static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
+                     const char *path, int argc, const char **argv)
 {
        pid_t pid;
        int save_errno, status, ret;
+       const char **new_argv;
+       int i;
+
+       new_argv = talloc_array(mem_ctx, const char *, argc + 2);
+       if (new_argv == NULL) {
+               return ENOMEM;
+       }
+
+       new_argv[0] = path;
+       for (i=0; i<argc; i++) {
+               new_argv[i+1] = argv[i];
+       }
+       new_argv[argc+1] = NULL;
 
        pid = fork();
        if (pid < 0) {
                save_errno = errno;
+               talloc_free(new_argv);
                fprintf(stderr, "Failed to fork %s (%s) - %s\n",
                        command, path, strerror(save_errno));
                return save_errno;
        }
 
        if (pid == 0) {
-               ret = execl(path, path, arg1, NULL);
+               ret = execv(path, discard_const(new_argv));
                if (ret == -1) {
-                       _exit(errno);
+                       _exit(64+errno);
                }
                /* Should not happen */
-               _exit(ENOEXEC);
+               _exit(64+ENOEXEC);
        }
 
+       talloc_free(new_argv);
+
        ret = waitpid(pid, &status, 0);
        if (ret == -1) {
                save_errno = errno;
@@ -675,11 +699,20 @@ static int run_helper(const char *command, const char *path, const char *arg1)
        }
 
        if (WIFEXITED(status)) {
-               ret = WEXITSTATUS(status);
+               int pstatus = WEXITSTATUS(status);
+               if (WIFSIGNALED(status)) {
+                       fprintf(stderr, "%s terminated with signal %d\n",
+                               command, WTERMSIG(status));
+                       ret = EINTR;
+               } else if (pstatus >= 64 && pstatus < 255) {
+                       fprintf(stderr, "%s failed with error %d\n",
+                               command, pstatus-64);
+                       ret = pstatus - 64;
+               } else {
+                       ret = pstatus;
+               }
                return ret;
-       }
-
-       if (WIFSIGNALED(status)) {
+       } else if (WIFSIGNALED(status)) {
                fprintf(stderr, "%s terminated with signal %d\n",
                        command, WTERMSIG(status));
                return EINTR;
@@ -695,7 +728,7 @@ static int run_helper(const char *command, const char *path, const char *arg1)
 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                           int argc, const char **argv)
 {
-       printf("%s\n", CTDB_VERSION_STRING);
+       printf("%s\n", SAMBA_VERSION_STRING);
        return 0;
 }
 
@@ -704,7 +737,8 @@ static bool partially_online(TALLOC_CTX *mem_ctx,
                             struct ctdb_node_and_flags *node)
 {
        struct ctdb_iface_list *iface_list;
-       int ret, i;
+       unsigned int i;
+       int ret;
        bool status = false;
 
        if (node->flags != 0) {
@@ -734,7 +768,7 @@ static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
                                  uint32_t mypnn)
 {
        struct ctdb_node_and_flags *node;
-       int i;
+       unsigned int i;
 
        printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
               options.sep,
@@ -758,7 +792,7 @@ static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
                printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
                       options.sep,
                       node->pnn, options.sep,
-                      ctdb_sock_addr_to_string(mem_ctx, &node->addr),
+                      ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
                       options.sep,
                       !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
                       !! (node->flags & NODE_FLAGS_BANNED), options.sep,
@@ -774,11 +808,12 @@ static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
 }
 
 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                         struct ctdb_node_map *nodemap, uint32_t mypnn)
+                         struct ctdb_node_map *nodemap, uint32_t mypnn,
+                         bool print_header)
 {
        struct ctdb_node_and_flags *node;
        int num_deleted_nodes = 0;
-       int i;
+       unsigned int i;
 
        for (i=0; i<nodemap->num; i++) {
                if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
@@ -786,11 +821,14 @@ static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                }
        }
 
-       if (num_deleted_nodes == 0) {
-               printf("Number of nodes:%d\n", nodemap->num);
-       } else {
-               printf("Number of nodes:%d (including %d deleted nodes)\n",
-                      nodemap->num, num_deleted_nodes);
+       if (print_header) {
+               if (num_deleted_nodes == 0) {
+                       printf("Number of nodes:%d\n", nodemap->num);
+               } else {
+                       printf("Number of nodes:%d "
+                              "(including %d deleted nodes)\n",
+                              nodemap->num, num_deleted_nodes);
+               }
        }
 
        for (i=0; i<nodemap->num; i++) {
@@ -801,7 +839,7 @@ static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
                printf("pnn:%u %-16s %s%s\n",
                       node->pnn,
-                      ctdb_sock_addr_to_string(mem_ctx, &node->addr),
+                      ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
                       partially_online(mem_ctx, ctdb, node) ?
                                "PARTIALLYONLINE" :
                                pretty_print_flags(mem_ctx, node->flags),
@@ -814,9 +852,9 @@ static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                         struct ctdb_vnn_map *vnnmap, int recmode,
                         uint32_t recmaster)
 {
-       int i;
+       unsigned int i;
 
-       print_nodemap(mem_ctx, ctdb, nodemap, mypnn);
+       print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
 
        if (vnnmap->generation == INVALID_GENERATION) {
                printf("Generation:INVALID\n");
@@ -1032,8 +1070,9 @@ static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        struct ctdb_var_list *tun_var_list;
        struct ctdb_tunable tunable;
-       int ret, i;
        bool found;
+       int i;
+       int ret = 0;
 
        if (argc != 2) {
                usage("setvar");
@@ -1062,7 +1101,10 @@ static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        tunable.name = argv[0];
-       tunable.value = strtoul(argv[1], NULL, 0);
+       tunable.value = smb_strtoul(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
+       if (ret != 0) {
+               return ret;
+       }
 
        ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
                                    ctdb->cmd_pnn, TIMEOUT(), &tunable);
@@ -1124,9 +1166,11 @@ const struct {
        STATISTICS_FIELD(node.req_message),
        STATISTICS_FIELD(node.req_control),
        STATISTICS_FIELD(node.reply_control),
+       STATISTICS_FIELD(node.req_tunnel),
        STATISTICS_FIELD(client.req_call),
        STATISTICS_FIELD(client.req_message),
        STATISTICS_FIELD(client.req_control),
+       STATISTICS_FIELD(client.req_tunnel),
        STATISTICS_FIELD(timeouts.call),
        STATISTICS_FIELD(timeouts.control),
        STATISTICS_FIELD(timeouts.traverse),
@@ -1149,7 +1193,7 @@ const struct {
 static void print_statistics_machine(struct ctdb_statistics *s,
                                     bool show_header)
 {
-       int i;
+       size_t i;
 
        if (show_header) {
                printf("CTDB version%s", options.sep);
@@ -1208,6 +1252,11 @@ static void print_statistics_machine(struct ctdb_statistics *s,
        printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
        printf("%.6f%s", s->call_latency.max, options.sep);
 
+       printf("%u%s", s->locks.latency.num, options.sep);
+       printf("%.6f%s", s->locks.latency.min, options.sep);
+       printf("%.6f%s", LATENCY_AVG(s->locks.latency), options.sep);
+       printf("%.6f%s", s->locks.latency.max, options.sep);
+
        printf("%d%s", s->childwrite_latency.num, options.sep);
        printf("%.6f%s", s->childwrite_latency.min, options.sep);
        printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
@@ -1218,7 +1267,7 @@ static void print_statistics_machine(struct ctdb_statistics *s,
 static void print_statistics(struct ctdb_statistics *s)
 {
        int tmp, days, hours, minutes, seconds;
-       int i;
+       size_t i;
        const char *prefix = NULL;
        int preflen = 0;
 
@@ -1374,12 +1423,20 @@ static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
+static int ctdb_public_ip_cmp(const void *a, const void *b)
+{
+       const struct ctdb_public_ip *ip_a = a;
+       const struct ctdb_public_ip *ip_b = b;
+
+       return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
+}
+
 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                     struct ctdb_public_ip_list *ips,
                     struct ctdb_public_ip_info **ipinfo,
                     bool all_nodes)
 {
-       int i, j;
+       unsigned int i, j;
        char *conf, *avail, *active;
 
        if (options.machinereadable == 1) {
@@ -1402,18 +1459,17 @@ static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                }
        }
 
-       /* IPs are reverse sorted */
-       for (i=ips->num-1; i>=0; i--) {
+       for (i = 0; i < ips->num; i++) {
 
                if (options.machinereadable == 1) {
                        printf("%s%s%s%d%s", options.sep,
                               ctdb_sock_addr_to_string(
-                                       mem_ctx, &ips->ip[i].addr),
+                                      mem_ctx, &ips->ip[i].addr, false),
                               options.sep,
                               (int)ips->ip[i].pnn, options.sep);
                } else {
                        printf("%s", ctdb_sock_addr_to_string(
-                                               mem_ctx, &ips->ip[i].addr));
+                                      mem_ctx, &ips->ip[i].addr, false));
                }
 
                if (options.verbose == 0) {
@@ -1429,6 +1485,10 @@ static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                avail = NULL;
                active = NULL;
 
+               if (ipinfo[i] == NULL) {
+                       goto skip_ipinfo;
+               }
+
                for (j=0; j<ipinfo[i]->ifaces->num; j++) {
                        struct ctdb_iface *iface;
 
@@ -1437,7 +1497,7 @@ static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                                conf = talloc_strdup(mem_ctx, iface->name);
                        } else {
                                conf = talloc_asprintf_append(
-                                               mem_ctx, ",%s", iface->name);
+                                               conf, ",%s", iface->name);
                        }
 
                        if (ipinfo[i]->active_idx == j) {
@@ -1452,18 +1512,21 @@ static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                                avail = talloc_strdup(mem_ctx, iface->name);
                        } else {
                                avail = talloc_asprintf_append(
-                                               mem_ctx, ",%s", iface->name);
+                                               avail, ",%s", iface->name);
                        }
                }
 
+       skip_ipinfo:
+
                if (options.machinereadable == 1) {
                        printf("%s%s%s%s%s%s\n",
                               active ? active : "", options.sep,
                               avail ? avail : "", options.sep,
                               conf ? conf : "", options.sep);
                } else {
-                       printf(" node[%u] active[%s] available[%s] configured[%s]\n",
-                              ips->ip[i].pnn, active ? active : "",
+                       printf(" node[%d] active[%s] available[%s]"
+                              " configured[%s]\n",
+                              (int)ips->ip[i].pnn, active ? active : "",
                               avail ? avail : "", conf ? conf : "");
                }
        }
@@ -1490,7 +1553,8 @@ static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
        struct ctdb_public_ip_list *ips;
        struct db_hash_context *ipdb;
        uint32_t *pnn_list;
-       int ret, count, i, j;
+       unsigned int j;
+       int ret, count, i;
 
        nodemap = get_nodemap(ctdb, false);
        if (nodemap == NULL) {
@@ -1510,7 +1574,8 @@ static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
 
        for (i=0; i<count; i++) {
                ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
-                                              pnn_list[i], TIMEOUT(), &ips);
+                                              pnn_list[i], TIMEOUT(),
+                                              false, &ips);
                if (ret != 0) {
                        goto failed;
                }
@@ -1521,11 +1586,34 @@ static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
                        ip.pnn = ips->ip[j].pnn;
                        ip.addr = ips->ip[j].addr;
 
-                       ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
-                                         sizeof(ip.addr),
-                                         (uint8_t *)&ip, sizeof(ip));
-                       if (ret != 0) {
-                               goto failed;
+                       if (pnn_list[i] == ip.pnn) {
+                               /* Node claims IP is hosted on it, so
+                                * save that information
+                                */
+                               ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
+                                                 sizeof(ip.addr),
+                                                 (uint8_t *)&ip, sizeof(ip));
+                               if (ret != 0) {
+                                       goto failed;
+                               }
+                       } else {
+                               /* Node thinks IP is hosted elsewhere,
+                                * so overwrite with CTDB_UNKNOWN_PNN
+                                * if there's no existing entry
+                                */
+                               ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
+                                                    sizeof(ip.addr));
+                               if (ret == ENOENT) {
+                                       ip.pnn = CTDB_UNKNOWN_PNN;
+                                       ret = db_hash_add(ipdb,
+                                                         (uint8_t *)&ip.addr,
+                                                         sizeof(ip.addr),
+                                                         (uint8_t *)&ip,
+                                                         sizeof(ip));
+                                       if (ret != 0) {
+                                               goto failed;
+                                       }
+                               }
                        }
                }
 
@@ -1554,7 +1642,7 @@ static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
                goto failed;
        }
 
-       if (count != ips->num) {
+       if ((unsigned int)count != ips->num) {
                goto failed;
        }
 
@@ -1573,7 +1661,8 @@ static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        struct ctdb_public_ip_list *ips;
        struct ctdb_public_ip_info **ipinfo;
-       int ret, i;
+       unsigned int i;
+       int ret;
        bool do_all = false;
 
        if (argc > 1) {
@@ -1592,12 +1681,16 @@ static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                ret = get_all_public_ips(ctdb, mem_ctx, &ips);
        } else {
                ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
-                                              ctdb->cmd_pnn, TIMEOUT(), &ips);
+                                              ctdb->cmd_pnn, TIMEOUT(),
+                                              false, &ips);
        }
        if (ret != 0) {
                return ret;
        }
 
+       qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
+             ctdb_public_ip_cmp);
+
        ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
        if (ipinfo == NULL) {
                return 1;
@@ -1610,6 +1703,10 @@ static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                } else {
                        pnn = ctdb->cmd_pnn;
                }
+               if (pnn == CTDB_UNKNOWN_PNN) {
+                       ipinfo[i] = NULL;
+                       continue;
+               }
                ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
                                                   ctdb->client, pnn,
                                                   TIMEOUT(), &ips->ip[i].addr,
@@ -1628,13 +1725,15 @@ static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        struct ctdb_public_ip_info *ipinfo;
        ctdb_sock_addr addr;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (argc != 1) {
                usage("ipinfo");
        }
 
-       if (! parse_ip(argv[0], NULL, 0, &addr)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
@@ -1651,11 +1750,11 @@ static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        printf("Public IP[%s] info on node %u\n",
-              ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
+              ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
                                        ctdb->cmd_pnn);
 
        printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
-              ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
+              ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
               ipinfo->ip.pnn, ipinfo->ifaces->num);
 
        for (i=0; i<ipinfo->ifaces->num; i++) {
@@ -1677,7 +1776,8 @@ static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                          int argc, const char **argv)
 {
        struct ctdb_iface_list *ifaces;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (argc != 0) {
                usage("ifaces");
@@ -1726,7 +1826,8 @@ static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        struct ctdb_iface_list *ifaces;
        struct ctdb_iface *iface;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (argc != 2) {
                usage("setifacelink");
@@ -1785,23 +1886,47 @@ static int control_process_exists(TALLOC_CTX *mem_ctx,
                                  int argc, const char **argv)
 {
        pid_t pid;
-       int ret, status;
+       uint64_t srvid = 0;
+       int status;
+       int ret = 0;
 
-       if (argc != 1) {
+       if (argc != 1 && argc != 2) {
                usage("process-exists");
        }
 
        pid = atoi(argv[0]);
-       ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
+       if (argc == 2) {
+               srvid = smb_strtoull(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+
+       if (srvid == 0) {
+               ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
                                       ctdb->cmd_pnn, TIMEOUT(), pid, &status);
+       } else {
+               struct ctdb_pid_srvid pid_srvid;
+
+               pid_srvid.pid = pid;
+               pid_srvid.srvid = srvid;
+
+               ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
+                                               ctdb->client, ctdb->cmd_pnn,
+                                               TIMEOUT(), &pid_srvid,
+                                               &status);
+       }
+
        if (ret != 0) {
                return ret;
        }
 
-       if (status == 0) {
-               printf("PID %u exists\n", pid);
+       if (srvid == 0) {
+               printf("PID %d %s\n", pid,
+                      (status == 0 ? "exists" : "does not exist"));
        } else {
-               printf("PID %u does not exist\n", pid);
+               printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
+                      (status == 0 ? "exists" : "does not exist"));
        }
        return status;
 }
@@ -1810,7 +1935,8 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                            int argc, const char **argv)
 {
        struct ctdb_dbid_map *dbmap;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (argc != 0) {
                usage("getdbmap");
@@ -1823,7 +1949,7 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        if (options.machinereadable == 1) {
-               printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+               printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
                       options.sep,
                       "ID", options.sep,
                       "Name", options.sep,
@@ -1831,7 +1957,8 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                       "Persistent", options.sep,
                       "Sticky", options.sep,
                       "Unhealthy", options.sep,
-                      "Readonly", options.sep);
+                      "Readonly", options.sep,
+                      "Replicated", options.sep);
        } else {
                printf("Number of databases:%d\n", dbmap->num);
        }
@@ -1843,6 +1970,7 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                bool persistent;
                bool readonly;
                bool sticky;
+               bool replicated;
                uint32_t db_id;
 
                db_id = dbmap->dbs[i].db_id;
@@ -1871,9 +1999,10 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
                readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
                sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
+               replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
 
                if (options.machinereadable == 1) {
-                       printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s\n",
+                       printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
                               options.sep,
                               db_id, options.sep,
                               name, options.sep,
@@ -1881,13 +2010,15 @@ static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                               !! (persistent), options.sep,
                               !! (sticky), options.sep,
                               !! (health), options.sep,
-                              !! (readonly), options.sep);
+                              !! (readonly), options.sep,
+                              !! (replicated), options.sep);
                } else {
-                       printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
+                       printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
                               db_id, name, path,
                               persistent ? " PERSISTENT" : "",
                               sticky ? " STICKY" : "",
                               readonly ? " READONLY" : "",
+                              replicated ? " REPLICATED" : "",
                               health ? " UNHEALTHY" : "");
                }
 
@@ -1930,11 +2061,12 @@ static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
-       printf("PERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
+       printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
               (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
+              (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
               (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
-              (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"),
-              (db_health ? db_health : "OK"));
+              (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
+       printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
        return 0;
 }
 
@@ -1946,7 +2078,7 @@ struct dump_record_state {
 
 static void dump_tdb_data(const char *name, TDB_DATA val)
 {
-       int i;
+       size_t i;
 
        fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
        for (i=0; i<val.dsize; i++) {
@@ -2005,50 +2137,6 @@ static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
        return 0;
 }
 
-struct traverse_state {
-       TALLOC_CTX *mem_ctx;
-       bool done;
-       ctdb_rec_parser_func_t func;
-       struct dump_record_state sub_state;
-};
-
-static void traverse_handler(uint64_t srvid, TDB_DATA data, void *private_data)
-{
-       struct traverse_state *state = (struct traverse_state *)private_data;
-       struct ctdb_rec_data *rec;
-       struct ctdb_ltdb_header header;
-       int ret;
-
-       ret = ctdb_rec_data_pull(data.dptr, data.dsize, state->mem_ctx, &rec);
-       if (ret != 0) {
-               return;
-       }
-
-       if (rec->key.dsize == 0 && rec->data.dsize == 0) {
-               talloc_free(rec);
-               /* end of traverse */
-               state->done = true;
-               return;
-       }
-
-       ret = ctdb_ltdb_header_extract(&rec->data, &header);
-       if (ret != 0) {
-               talloc_free(rec);
-               return;
-       }
-
-       if (rec->data.dsize == 0) {
-               return;
-       }
-
-       ret = state->func(rec->reqid, &header, rec->key, rec->data,
-                         &state->sub_state);
-       talloc_free(rec);
-       if (ret != 0) {
-               state->done = true;
-       }
-}
-
 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                         int argc, const char **argv)
 {
@@ -2056,8 +2144,7 @@ static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        const char *db_name;
        uint32_t db_id;
        uint8_t db_flags;
-       struct ctdb_traverse_start_ext traverse;
-       struct traverse_state state;
+       struct dump_record_state state;
        int ret;
 
        if (argc != 1) {
@@ -2075,44 +2162,15 @@ static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return ret;
        }
 
-       /* Valgrind fix */
-       ZERO_STRUCT(traverse);
-
-       traverse.db_id = db_id;
-       traverse.reqid = 0;
-       traverse.srvid = next_srvid(ctdb);
-       traverse.withemptyrecords = false;
-
-       state.mem_ctx = mem_ctx;
-       state.done = false;
-       state.func = dump_record;
-       state.sub_state.count = 0;
-
-       ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
-                                             traverse.srvid,
-                                             traverse_handler, &state);
-       if (ret != 0) {
-               return ret;
-       }
-
-       ret = ctdb_ctrl_traverse_start_ext(mem_ctx, ctdb->ev, ctdb->client,
-                                          ctdb->cmd_pnn, TIMEOUT(),
-                                          &traverse);
-       if (ret != 0) {
-               return ret;
-       }
-
-       ctdb_client_wait(ctdb->ev, &state.done);
+       state.count = 0;
 
-       printf("Dumped %u records\n", state.sub_state.count);
+       ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
+                              ctdb->cmd_pnn, TIMEOUT(),
+                              dump_record, &state);
 
-       ret = ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
-                                                traverse.srvid, &state);
-       if (ret != 0) {
-               return ret;
-       }
+       printf("Dumped %u records\n", state.count);
 
-       return 0;
+       return ret;
 }
 
 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
@@ -2126,7 +2184,7 @@ static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        int ret;
 
        if (argc != 1) {
-               usage("catdb");
+               usage("cattdb");
        }
 
        if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
@@ -2141,33 +2199,13 @@ static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        state.count = 0;
-       ret = ctdb_db_traverse(db, true, true, dump_record, &state);
+       ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
 
        printf("Dumped %u record(s)\n", state.count);
 
        return ret;
 }
 
-static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                             int argc, const char **argv)
-{
-       int mode, ret;
-
-       if (argc != 0) {
-               usage("getmonmode");
-       }
-
-       ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
-                                   ctdb->cmd_pnn, TIMEOUT(), &mode);
-       if (ret != 0) {
-               return ret;
-       }
-
-       printf("%s\n",
-              (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
-       return 0;
-}
-
 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
                                   struct ctdb_context *ctdb,
                                   int argc, const char **argv)
@@ -2232,51 +2270,13 @@ static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       return run_helper("LVS helper", lvs_helper, argv[0]);
-}
-
-static int control_disable_monitor(TALLOC_CTX *mem_ctx,
-                                  struct ctdb_context *ctdb,
-                                  int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 0) {
-               usage("disablemonitor");
-       }
-
-       ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
-                                       ctdb->cmd_pnn, TIMEOUT());
-       if (ret != 0) {
-               return ret;
-       }
-
-       return 0;
-}
-
-static int control_enable_monitor(TALLOC_CTX *mem_ctx,
-                                 struct ctdb_context *ctdb,
-                                 int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 0) {
-               usage("enablemonitor");
-       }
-
-       ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
-                                      ctdb->cmd_pnn, TIMEOUT());
-       if (ret != 0) {
-               return ret;
-       }
-
-       return 0;
+       return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
 }
 
 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                            int argc, const char **argv)
 {
-       enum debug_level log_level;
+       int log_level;
        int ret;
        bool found;
 
@@ -2305,7 +2305,7 @@ static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                            int argc, const char **argv)
 {
-       enum debug_level loglevel;
+       int loglevel;
        const char *log_str;
        int ret;
 
@@ -2344,6 +2344,8 @@ static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                        db_flags = CTDB_DB_FLAGS_READONLY;
                } else if (strcmp(argv[1], "sticky") == 0) {
                        db_flags = CTDB_DB_FLAGS_STICKY;
+               } else if (strcmp(argv[1], "replicated") == 0) {
+                       db_flags = CTDB_DB_FLAGS_REPLICATED;
                } else {
                        usage("attach");
                }
@@ -2366,6 +2368,7 @@ static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        uint8_t db_flags;
        struct ctdb_node_map *nodemap;
        int recmode;
+       unsigned int j;
        int ret, ret2, i;
 
        if (argc < 1) {
@@ -2389,29 +2392,29 @@ static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       for (i=0; i<nodemap->num; i++) {
+       for (j=0; j<nodemap->num; j++) {
                uint32_t value;
 
-               if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
+               if (nodemap->node[j].flags & NODE_FLAGS_DISCONNECTED) {
                        continue;
                }
-               if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
+               if (nodemap->node[j].flags & NODE_FLAGS_DELETED) {
                        continue;
                }
-               if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
+               if (nodemap->node[j].flags & NODE_FLAGS_INACTIVE) {
                        fprintf(stderr, "Database cannot be detached on"
                                " inactive (stopped or banned) node %u\n",
-                               nodemap->node[i].pnn);
+                               nodemap->node[j].pnn);
                        return 1;
                }
 
                ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
-                                           nodemap->node[i].pnn, TIMEOUT(),
+                                           nodemap->node[j].pnn, TIMEOUT(),
                                            "AllowClientDBAttach", &value);
                if (ret != 0) {
                        fprintf(stderr,
                                "Unable to get tunable AllowClientDBAttach"
-                               " from node %u\n", nodemap->node[i].pnn);
+                               " from node %u\n", nodemap->node[j].pnn);
                        return ret;
                }
 
@@ -2419,7 +2422,7 @@ static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                        fprintf(stderr,
                                "Database access is still active on node %u."
                                " Set AllowclientDBAttach=0 on all nodes.\n",
-                               nodemap->node[i].pnn);
+                               nodemap->node[j].pnn);
                        return 1;
                }
        }
@@ -2431,15 +2434,14 @@ static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                        continue;
                }
 
-               if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
+               if (db_flags &
+                   (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
                        fprintf(stderr,
-                               "Persistent database %s cannot be detached\n",
-                               argv[0]);
+                               "Only volatile databases can be detached\n");
                        return 1;
                }
 
-               ret = ctdb_detach(mem_ctx, ctdb->ev, ctdb->client,
-                                 TIMEOUT(), db_id);
+               ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
                if (ret != 0) {
                        fprintf(stderr, "Database %s detach failed\n", db_name);
                        ret2 = ret;
@@ -2462,8 +2464,8 @@ static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return ret;
        }
 
-       n = write(1, mem_str, strlen(mem_str)+1);
-       if (n < 0 || n != strlen(mem_str)+1) {
+       n = write(1, mem_str, strlen(mem_str));
+       if (n < 0 || (size_t)n != strlen(mem_str)) {
                fprintf(stderr, "Failed to write talloc summary\n");
                return 1;
        }
@@ -2474,10 +2476,12 @@ static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
 {
        bool *done = (bool *)private_data;
+       size_t len;
        ssize_t n;
 
-       n = write(1, data.dptr, data.dsize);
-       if (n < 0 || n != data.dsize) {
+       len = strnlen((const char *)data.dptr, data.dsize);
+       n = write(1, data.dptr, len);
+       if (n < 0 || (size_t)n != len) {
                fprintf(stderr, "Failed to write talloc summary\n");
        }
 
@@ -2576,6 +2580,40 @@ static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 }
 
+static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+                             struct ctdb_client_context *client,
+                             uint32_t destnode, struct timeval timeout,
+                             uint32_t set, uint32_t clear)
+{
+       struct ctdb_node_map *nodemap;
+       struct ctdb_node_flag_change flag_change;
+       struct ctdb_req_control request;
+       uint32_t *pnn_list;
+       int ret, count;
+
+       ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
+                                   tevent_timeval_zero(), &nodemap);
+       if (ret != 0) {
+               return ret;
+       }
+
+       flag_change.pnn = destnode;
+       flag_change.old_flags = nodemap->node[destnode].flags;
+       flag_change.new_flags = flag_change.old_flags | set;
+       flag_change.new_flags &= ~clear;
+
+       count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
+       if (count == -1) {
+               return ENOMEM;
+       }
+
+       ctdb_req_control_modify_flags(&request, &flag_change);
+       ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
+                                       tevent_timeval_zero(), &request,
+                                       NULL, NULL);
+       return ret;
+}
+
 struct ipreallocate_state {
        int status;
        bool done;
@@ -2756,7 +2794,7 @@ static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                       int argc, const char **argv)
 {
        struct ctdb_ban_state ban_state;
-       int ret;
+       int ret = 0;
 
        if (argc != 1) {
                usage("ban");
@@ -2769,7 +2807,10 @@ static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        ban_state.pnn = ctdb->cmd_pnn;
-       ban_state.time = strtoul(argv[0], NULL, 0);
+       ban_state.time = smb_strtoul(argv[0], NULL, 0, &ret, SMB_STR_STANDARD);
+       if (ret != 0) {
+               return ret;
+       }
 
        if (ban_state.time == 0) {
                fprintf(stderr, "Ban time cannot be zero\n");
@@ -2819,15 +2860,29 @@ static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
 }
 
+static void wait_for_shutdown(void *private_data)
+{
+       bool *done = (bool *)private_data;
+
+       *done = true;
+}
+
 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                            int argc, const char **argv)
 {
        int ret;
+       bool done = false;
 
        if (argc != 0) {
                usage("shutdown");
        }
 
+       if (ctdb->pnn == ctdb->cmd_pnn) {
+               ctdb_client_set_disconnect_callback(ctdb->client,
+                                                   wait_for_shutdown,
+                                                   &done);
+       }
+
        ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
                                 ctdb->cmd_pnn, TIMEOUT());
        if (ret != 0) {
@@ -2835,6 +2890,10 @@ static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return ret;
        }
 
+       if (ctdb->pnn == ctdb->cmd_pnn) {
+               ctdb_client_wait(ctdb->ev, &done);
+       }
+
        return 0;
 }
 
@@ -2875,7 +2934,7 @@ again:
                return ret;
        }
 
-       if (vnnmap->generation == 1) {
+       if (vnnmap->generation == INVALID_GENERATION) {
                talloc_free(vnnmap);
                sleep(1);
                goto again;
@@ -2938,33 +2997,6 @@ static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return ipreallocate(mem_ctx, ctdb);
 }
 
-static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
-                                 struct ctdb_context *ctdb,
-                                 int argc, const char **argv)
-{
-       uint32_t recmaster;
-       int ret;
-
-       if (argc != 0) {
-               usage("isnotrecmaster");
-       }
-
-       ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
-                                     ctdb->pnn, TIMEOUT(), &recmaster);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to get recmaster\n");
-               return ret;
-       }
-
-       if (recmaster != ctdb->pnn) {
-               printf("this node is not the recmaster\n");
-               return 1;
-       }
-
-       printf("this node is the recmaster\n");
-       return 0;
-}
-
 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                           int argc, const char **argv)
 {
@@ -2975,7 +3007,8 @@ static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                usage("gratarp");
        }
 
-       if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
@@ -3004,25 +3037,28 @@ static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        if (argc == 0) {
-               struct ctdb_connection *clist;
-               int count;
-               int i, num_failed;
+               struct ctdb_connection_list *clist;
+               unsigned int i;
+               unsigned int num_failed;
 
-               ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
+               /* Client first but the src/dst logic is confused */
+               ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
                if (ret != 0) {
                        return ret;
                }
 
                num_failed = 0;
-               for (i=0; i<count; i++) {
-                       ret = ctdb_sys_send_tcp(&clist[i].src,
-                                               &clist[i].dst,
+               for (i = 0; i < clist->num; i++) {
+                       ret = ctdb_sys_send_tcp(&clist->conn[i].src,
+                                               &clist->conn[i].dst,
                                                0, 0, 0);
                        if (ret != 0) {
                                num_failed += 1;
                        }
                }
 
+               TALLOC_FREE(clist);
+
                if (num_failed > 0) {
                        fprintf(stderr, "Failed to send %d tickles\n",
                                num_failed);
@@ -3033,12 +3069,14 @@ static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
 
-       if (! parse_ip_port(argv[0], &src)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &src, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
 
-       if (! parse_ip_port(argv[1], &dst)) {
+       ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[1]);
                return 1;
        }
@@ -3058,20 +3096,26 @@ static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        ctdb_sock_addr addr;
        struct ctdb_tickle_list *tickles;
        unsigned port = 0;
-       int ret, i;
+       unsigned int i;
+       int ret = 0;
 
        if (argc < 1 || argc > 2) {
                usage("gettickles");
        }
 
        if (argc == 2) {
-               port = strtoul(argv[1], NULL, 10);
+               port = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
+               if (ret != 0) {
+                       return ret;
+               }
        }
 
-       if (! parse_ip(argv[0], NULL, port, &addr)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
+       ctdb_sock_addr_set_port(&addr, port);
 
        ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
                                            ctdb->cmd_pnn, TIMEOUT(), &addr,
@@ -3091,31 +3135,31 @@ static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                for (i=0; i<tickles->num; i++) {
                        printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
                               ctdb_sock_addr_to_string(
-                                      mem_ctx, &tickles->conn[i].src),
+                                      mem_ctx, &tickles->conn[i].src, false),
                               options.sep,
                               ntohs(tickles->conn[i].src.ip.sin_port),
                               options.sep,
                               ctdb_sock_addr_to_string(
-                                      mem_ctx, &tickles->conn[i].dst),
+                                      mem_ctx, &tickles->conn[i].dst, false),
                               options.sep,
                               ntohs(tickles->conn[i].dst.ip.sin_port),
                               options.sep);
                }
        } else {
                printf("Connections for IP: %s\n",
-                      ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
+                      ctdb_sock_addr_to_string(mem_ctx,
+                                               &tickles->addr, false));
                printf("Num connections: %u\n", tickles->num);
                for (i=0; i<tickles->num; i++) {
-                       printf("SRC: %s:%u   DST: %s:%u\n",
+                       printf("SRC: %s   DST: %s\n",
                               ctdb_sock_addr_to_string(
-                                      mem_ctx, &tickles->conn[i].src),
-                              ntohs(tickles->conn[i].src.ip.sin_port),
+                                      mem_ctx, &tickles->conn[i].src, true),
                               ctdb_sock_addr_to_string(
-                                      mem_ctx, &tickles->conn[i].dst),
-                              ntohs(tickles->conn[i].dst.ip.sin_port));
+                                      mem_ctx, &tickles->conn[i].dst, true));
                }
        }
 
+       talloc_free(tickles);
        return 0;
 }
 
@@ -3125,9 +3169,9 @@ typedef void (*clist_request_func)(struct ctdb_req_control *request,
 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
 
 struct process_clist_state {
-       struct ctdb_connection *clist;
+       struct ctdb_connection_list *clist;
        int count;
-       int num_failed, num_total;
+       unsigned int num_failed, num_total;
        clist_reply_func reply_func;
 };
 
@@ -3136,15 +3180,14 @@ static void process_clist_done(struct tevent_req *subreq);
 static struct tevent_req *process_clist_send(
                                        TALLOC_CTX *mem_ctx,
                                        struct ctdb_context *ctdb,
-                                       struct ctdb_connection *clist,
-                                       int count,
+                                       struct ctdb_connection_list *clist,
                                        clist_request_func request_func,
                                        clist_reply_func reply_func)
 {
        struct tevent_req *req, *subreq;
        struct process_clist_state *state;
        struct ctdb_req_control request;
-       int i;
+       unsigned int i;
 
        req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
        if (req == NULL) {
@@ -3152,11 +3195,10 @@ static struct tevent_req *process_clist_send(
        }
 
        state->clist = clist;
-       state->count = count;
        state->reply_func = reply_func;
 
-       for (i=0; i<count; i++) {
-               request_func(&request, &clist[i]);
+       for (i = 0; i < clist->num; i++) {
+               request_func(&request, &clist->conn[i]);
                subreq = ctdb_client_control_send(state, ctdb->ev,
                                                  ctdb->client, ctdb->cmd_pnn,
                                                  TIMEOUT(), &request);
@@ -3194,7 +3236,7 @@ static void process_clist_done(struct tevent_req *subreq)
 
 done:
        state->num_total += 1;
-       if (state->num_total == state->count) {
+       if (state->num_total == state->clist->num) {
                tevent_req_done(req);
        }
 }
@@ -3218,23 +3260,28 @@ static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        if (argc == 0) {
-               struct ctdb_connection *clist;
+               struct ctdb_connection_list *clist;
                struct tevent_req *req;
-               int count;
 
-               ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
+               /* Client first but the src/dst logic is confused */
+               ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
                if (ret != 0) {
                        return ret;
                }
+               if (clist->num == 0) {
+                       return 0;
+               }
 
-               req = process_clist_send(mem_ctx, ctdb, clist, count,
+               req = process_clist_send(mem_ctx, ctdb, clist,
                                 ctdb_req_control_tcp_add_delayed_update,
                                 ctdb_reply_control_tcp_add_delayed_update);
                if (req == NULL) {
+                       talloc_free(clist);
                        return ENOMEM;
                }
 
                tevent_req_poll(req, ctdb->ev);
+               talloc_free(clist);
 
                ret = process_clist_recv(req);
                if (ret != 0) {
@@ -3245,11 +3292,13 @@ static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 0;
        }
 
-       if (! parse_ip_port(argv[0], &conn.src)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
-       if (! parse_ip_port(argv[1], &conn.dst)) {
+       ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[1]);
                return 1;
        }
@@ -3276,23 +3325,28 @@ static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        if (argc == 0) {
-               struct ctdb_connection *clist;
+               struct ctdb_connection_list *clist;
                struct tevent_req *req;
-               int count;
 
-               ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
+               /* Client first but the src/dst logic is confused */
+               ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
                if (ret != 0) {
                        return ret;
                }
+               if (clist->num == 0) {
+                       return 0;
+               }
 
-               req = process_clist_send(mem_ctx, ctdb, clist, count,
+               req = process_clist_send(mem_ctx, ctdb, clist,
                                         ctdb_req_control_tcp_remove,
                                         ctdb_reply_control_tcp_remove);
                if (req == NULL) {
+                       talloc_free(clist);
                        return ENOMEM;
                }
 
                tevent_req_poll(req, ctdb->ev);
+               talloc_free(clist);
 
                ret = process_clist_recv(req);
                if (ret != 0) {
@@ -3303,11 +3357,13 @@ static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 0;
        }
 
-       if (! parse_ip_port(argv[0], &conn.src)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
-       if (! parse_ip_port(argv[1], &conn.dst)) {
+       ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[1]);
                return 1;
        }
@@ -3322,49 +3378,11 @@ static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
-static int control_check_srvids(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                               int argc, const char **argv)
-{
-       uint64_t *srvid;
-       uint8_t *result;
-       int ret, i;
-
-       if (argc == 0) {
-               usage("check_srvids");
-       }
-
-       srvid = talloc_array(mem_ctx, uint64_t, argc);
-       if (srvid == NULL) {
-               fprintf(stderr, "Memory allocation error\n");
-               return 1;
-       }
-
-       for (i=0; i<argc; i++) {
-               srvid[i] = strtoull(argv[i], NULL, 0);
-       }
-
-       ret = ctdb_ctrl_check_srvids(mem_ctx, ctdb->ev, ctdb->client,
-                                    ctdb->cmd_pnn, TIMEOUT(), srvid, argc,
-                                    &result);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to check srvids on node %u\n",
-                       ctdb->cmd_pnn);
-               return ret;
-       }
-
-       for (i=0; i<argc; i++) {
-               printf("SRVID 0x%" PRIx64 " %s\n", srvid[i],
-                      (result[i] ? "exists" : "does not exist"));
-       }
-
-       return 0;
-}
-
 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                             int argc, const char **argv)
 {
        struct ctdb_node_map *nodemap;
-       int i;
+       unsigned int i;
 
        if (argc != 0) {
                usage("listnodes");
@@ -3384,12 +3402,12 @@ static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                        printf("%s%u%s%s%s\n", options.sep,
                               nodemap->node[i].pnn, options.sep,
                               ctdb_sock_addr_to_string(
-                                       mem_ctx, &nodemap->node[i].addr),
+                                      mem_ctx, &nodemap->node[i].addr, false),
                               options.sep);
                } else {
                        printf("%s\n",
                               ctdb_sock_addr_to_string(
-                                       mem_ctx, &nodemap->node[i].addr));
+                                      mem_ctx, &nodemap->node[i].addr, false));
                }
        }
 
@@ -3399,7 +3417,7 @@ static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
                              struct ctdb_node_map *nodemap2)
 {
-       int i;
+       unsigned int i;
 
        if (nodemap1->num != nodemap2->num) {
                return false;
@@ -3426,7 +3444,7 @@ static int check_node_file_changes(TALLOC_CTX *mem_ctx,
                                   struct ctdb_node_map *fnm,
                                   bool *reload)
 {
-       int i;
+       unsigned int i;
        bool check_failed = false;
 
        *reload = false;
@@ -3437,7 +3455,7 @@ static int check_node_file_changes(TALLOC_CTX *mem_ctx,
                                "Node %u (%s) missing from nodes file\n",
                                nm->node[i].pnn,
                                ctdb_sock_addr_to_string(
-                                       mem_ctx, &nm->node[i].addr));
+                                       mem_ctx, &nm->node[i].addr, false));
                        check_failed = true;
                        continue;
                }
@@ -3457,9 +3475,11 @@ static int check_node_file_changes(TALLOC_CTX *mem_ctx,
                                        " (was %s, now %s)\n",
                                        nm->node[i].pnn,
                                        ctdb_sock_addr_to_string(
-                                               mem_ctx, &nm->node[i].addr),
+                                               mem_ctx,
+                                               &nm->node[i].addr, false),
                                        ctdb_sock_addr_to_string(
-                                               mem_ctx, &fnm->node[i].addr));
+                                               mem_ctx,
+                                               &fnm->node[i].addr, false));
                                check_failed = true;
                        } else {
                                if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
@@ -3509,7 +3529,7 @@ static int check_node_file_changes(TALLOC_CTX *mem_ctx,
 
 struct disable_recoveries_state {
        uint32_t *pnn_list;
-       int node_count;
+       unsigned int node_count;
        bool *reply;
        int status;
        bool done;
@@ -3520,7 +3540,8 @@ static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
 {
        struct disable_recoveries_state *state =
                (struct disable_recoveries_state *)private_data;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (data.dsize != sizeof(int)) {
                /* Ignore packet */
@@ -3535,7 +3556,7 @@ static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
                return;
        }
        for (i=0; i<state->node_count; i++) {
-               if (state->pnn_list[i] == ret) {
+               if (state->pnn_list[i] == (uint32_t)ret) {
                        state->reply[i] = true;
                        break;
                }
@@ -3610,9 +3631,10 @@ static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct ctdb_req_control request;
        struct ctdb_reply_control **reply;
        bool reload;
-       int ret, i;
-       uint32_t *pnn_list;
+       unsigned int i;
        int count;
+       int ret;
+       uint32_t *pnn_list;
 
        nodemap = get_nodemap(ctdb, false);
        if (nodemap == NULL) {
@@ -3679,13 +3701,14 @@ static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                                        &request, NULL, &reply);
        if (ret != 0) {
                bool failed = false;
+               int j;
 
-               for (i=0; i<count; i++) {
-                       ret = ctdb_reply_control_reload_nodes_file(reply[i]);
+               for (j=0; j<count; j++) {
+                       ret = ctdb_reply_control_reload_nodes_file(reply[j]);
                        if (ret != 0) {
                                fprintf(stderr,
                                        "Node %u failed to reload nodes\n",
-                                       pnn_list[i]);
+                                       pnn_list[j]);
                                failed = true;
                        }
                }
@@ -3712,7 +3735,8 @@ static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct ctdb_node_map *nodemap;
        struct ctdb_req_control request;
        uint32_t *pnn_list;
-       int ret, i, count;
+       unsigned int i;
+       int ret, count;
 
        ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
                                            CTDB_BROADCAST_CONNECTED,
@@ -3723,7 +3747,7 @@ static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
-                                      pnn, TIMEOUT(), &pubip_list);
+                                      pnn, TIMEOUT(), false, &pubip_list);
        if (ret != 0) {
                fprintf(stderr, "Failed to get Public IPs from node %u\n",
                        pnn);
@@ -3738,7 +3762,7 @@ static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
        if (i == pubip_list->num) {
                fprintf(stderr, "Node %u CANNOT host IP address %s\n",
-                       pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
+                       pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
                return 1;
        }
 
@@ -3780,19 +3804,21 @@ static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        ctdb_sock_addr addr;
        uint32_t pnn;
-       int ret, retries = 0;
+       int retries = 0;
+       int ret = 0;
 
        if (argc != 2) {
                usage("moveip");
        }
 
-       if (! parse_ip(argv[0], NULL, 0, &addr)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
 
-       pnn = strtoul(argv[1], NULL, 10);
-       if (pnn == CTDB_UNKNOWN_PNN) {
+       pnn = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
+       if (pnn == CTDB_UNKNOWN_PNN || ret != 0) {
                fprintf(stderr, "Invalid PNN %s\n", argv[1]);
                return 1;
        }
@@ -3816,59 +3842,6 @@ static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
-static int control_rebalanceip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                              int argc, const char **argv)
-{
-       ctdb_sock_addr addr;
-       struct ctdb_node_map *nodemap;
-       struct ctdb_public_ip pubip;
-       struct ctdb_req_control request;
-       uint32_t *pnn_list;
-       int ret, count;
-
-       if (argc != 1) {
-               usage("rebalanceip");
-       }
-
-       if (parse_ip(argv[0], NULL, 0, &addr)) {
-               fprintf(stderr, "Invalid IP address %s\n", argv[0]);
-               return 1;
-       }
-
-       ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
-                                           CTDB_BROADCAST_CONNECTED,
-                                           2*options.timelimit);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to disable IP check\n");
-               return 1;
-       }
-
-       nodemap = get_nodemap(ctdb, false);
-       if (nodemap == NULL) {
-               return 1;
-       }
-
-       count = list_of_active_nodes(nodemap, -1, mem_ctx, &pnn_list);
-       if (count <= 0) {
-               fprintf(stderr, "Memory allocation error\n");
-               return 1;
-       }
-
-       pubip.pnn = CTDB_UNKNOWN_PNN;
-       pubip.addr = addr;
-
-       ctdb_req_control_release_ip(&request, &pubip);
-       ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
-                                       pnn_list, count, TIMEOUT(),
-                                       &request, NULL, NULL);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to release IP from nodes\n");
-               return 1;
-       }
-
-       return ipreallocate(mem_ctx, ctdb);
-}
-
 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                         uint32_t pnn)
 {
@@ -3891,20 +3864,22 @@ static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        ctdb_sock_addr addr;
        struct ctdb_public_ip_list *pubip_list;
        struct ctdb_addr_info addr_info;
-       unsigned int mask;
-       int ret, i, retries = 0;
+       unsigned int mask, i;
+       int ret, retries = 0;
 
        if (argc != 2) {
                usage("addip");
        }
 
-       if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
+       ret = ctdb_sock_addr_mask_from_string(argv[0], &addr, &mask);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
                return 1;
        }
 
        ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
-                                      ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
+                                      ctdb->cmd_pnn, TIMEOUT(),
+                                      false, &pubip_list);
        if (ret != 0) {
                fprintf(stderr, "Failed to get Public IPs from node %u\n",
                        ctdb->cmd_pnn);
@@ -3914,7 +3889,8 @@ static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        for (i=0; i<pubip_list->num; i++) {
                if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
                        fprintf(stderr, "Node already knows about IP %s\n",
-                               ctdb_sock_addr_to_string(mem_ctx, &addr));
+                               ctdb_sock_addr_to_string(mem_ctx,
+                                                        &addr, false));
                        return 0;
                }
        }
@@ -3946,7 +3922,7 @@ static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return ret;
        }
 
-       return ipreallocate(mem_ctx, ctdb);
+       return 0;
 }
 
 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
@@ -3955,19 +3931,22 @@ static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        ctdb_sock_addr addr;
        struct ctdb_public_ip_list *pubip_list;
        struct ctdb_addr_info addr_info;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (argc != 1) {
                usage("delip");
        }
 
-       if (! parse_ip(argv[0], NULL, 0, &addr)) {
+       ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
+       if (ret != 0) {
                fprintf(stderr, "Invalid IP address %s\n", argv[0]);
                return 1;
        }
 
        ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
-                                      ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
+                                      ctdb->cmd_pnn, TIMEOUT(),
+                                      false, &pubip_list);
        if (ret != 0) {
                fprintf(stderr, "Failed to get Public IPs from node %u\n",
                        ctdb->cmd_pnn);
@@ -3982,7 +3961,7 @@ static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
        if (i == pubip_list->num) {
                fprintf(stderr, "Node does not know about IP address %s\n",
-                       ctdb_sock_addr_to_string(mem_ctx, &addr));
+                       ctdb_sock_addr_to_string(mem_ctx, &addr, false));
                return 0;
        }
 
@@ -4001,31 +3980,6 @@ static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
-static int control_eventscript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                              int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 1) {
-               usage("eventscript");
-       }
-
-       if (strcmp(argv[0], "monitor") != 0) {
-               fprintf(stderr, "Only monitor event can be run\n");
-               return 1;
-       }
-
-       ret = ctdb_ctrl_run_eventscripts(mem_ctx, ctdb->ev, ctdb->client,
-                                        ctdb->cmd_pnn, TIMEOUT(), argv[0]);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to run monitor event on node %u\n",
-                       ctdb->cmd_pnn);
-               return ret;
-       }
-
-       return 0;
-}
-
 #define DB_VERSION     3
 #define MAX_DB_NAME    64
 #define MAX_REC_BUFFER_SIZE    (100*1000)
@@ -4136,7 +4090,7 @@ static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        state.nbuf = 0;
        state.nrec = 0;
 
-       ret = ctdb_db_traverse(db, true, false, backup_handler, &state);
+       ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
        if (ret != 0) {
                fprintf(stderr, "Failed to collect records from DB %s\n",
                        db_name);
@@ -4194,8 +4148,11 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        uint32_t generation;
        uint32_t *pnn_list;
        char timebuf[128];
-       int fd, i;
-       int count, ret;
+       ssize_t n;
+       int fd;
+       unsigned long i, count;
+       int ret;
+       uint8_t db_flags;
 
        if (argc < 1 || argc > 2) {
                usage("restoredb");
@@ -4213,14 +4170,15 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                db_name = argv[1];
        }
 
-       ret = read(fd, &db_hdr, sizeof(struct db_header));
-       if (ret == -1) {
+       n = read(fd, &db_hdr, sizeof(struct db_header));
+       if (n == -1) {
                ret = errno;
                close(fd);
                fprintf(stderr, "Failed to read db header from file %s\n",
                        argv[0]);
                return ret;
        }
+       db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
 
        if (db_hdr.version != DB_VERSION) {
                fprintf(stderr,
@@ -4238,10 +4196,12 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                 localtime(&db_hdr.timestamp));
        printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
 
+       db_flags = db_hdr.flags & 0xff;
        ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
-                         db_hdr.flags, &db);
+                         db_flags, &db);
        if (ret != 0) {
-               fprintf(stderr, "Failed to attach to DB %s\n", db_hdr.name);
+               fprintf(stderr, "Failed to attach to DB %s\n", db_name);
+               close(fd);
                return ret;
        }
 
@@ -4309,6 +4269,7 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        for (i=0; i<db_hdr.nbuf; i++) {
                struct ctdb_req_message message;
                TDB_DATA data;
+               size_t np;
 
                ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
                if (ret != 0) {
@@ -4321,7 +4282,7 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                        goto failed;
                }
 
-               ctdb_rec_buffer_push(recbuf, data.dptr);
+               ctdb_rec_buffer_push(recbuf, data.dptr, &np);
 
                message.srvid = pulldb.srvid;
                message.data.data = data;
@@ -4389,6 +4350,7 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        printf("Database %s restored\n", db_name);
+       close(fd);
        return 0;
 
 
@@ -4428,7 +4390,9 @@ static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct db_header db_hdr;
        char timebuf[128];
        struct dumpdbbackup_state state;
-       int fd, ret, i;
+       ssize_t n;
+       unsigned long i;
+       int fd, ret;
 
        if (argc != 1) {
                usage("dumpbackup");
@@ -4442,19 +4406,21 @@ static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return ret;
        }
 
-       ret = read(fd, &db_hdr, sizeof(struct db_header));
-       if (ret == -1) {
+       n = read(fd, &db_hdr, sizeof(struct db_header));
+       if (n == -1) {
                ret = errno;
                close(fd);
                fprintf(stderr, "Failed to read db header from file %s\n",
                        argv[0]);
                return ret;
        }
+       db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
 
        if (db_hdr.version != DB_VERSION) {
                fprintf(stderr,
                        "Wrong version of backup file, expected %u, got %lu\n",
                        DB_VERSION, db_hdr.version);
+               close(fd);
                return EINVAL;
        }
 
@@ -4472,6 +4438,7 @@ static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
                if (ret != 0) {
                        fprintf(stderr, "Failed to read records\n");
+                       close(fd);
                        return ret;
                }
 
@@ -4479,10 +4446,12 @@ static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                                               &state);
                if (ret != 0) {
                        fprintf(stderr, "Failed to dump records\n");
+                       close(fd);
                        return ret;
                }
        }
 
+       close(fd);
        printf("Dumped %u record(s)\n", state.sub_state.count);
        return 0;
 }
@@ -4611,239 +4580,43 @@ static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
-static void print_scriptstatus_one(struct ctdb_script_list *slist,
-                                  const char *event_str)
+static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
+                        int argc, const char **argv)
 {
-       int i;
-       int num_run = 0;
+       char *t, *event_helper = NULL;
 
-       if (slist == NULL) {
-               if (! options.machinereadable) {
-                       printf("%s cycle never run\n", event_str);
-               }
-               return;
-       }
-
-       for (i=0; i<slist->num_scripts; i++) {
-               if (slist->script[i].status != -ENOEXEC) {
-                       num_run++;
-               }
-       }
-
-       if (! options.machinereadable) {
-               printf("%d scripts were executed last %s cycle\n",
-                      num_run, event_str);
-       }
-
-       for (i=0; i<slist->num_scripts; i++) {
-               const char *status = NULL;
-
-               switch (slist->script[i].status) {
-               case -ETIME:
-                       status = "TIMEDOUT";
-                       break;
-               case -ENOEXEC:
-                       status = "DISABLED";
-                       break;
-               case 0:
-                       status = "OK";
-                       break;
-               default:
-                       if (slist->script[i].status > 0) {
-                               status = "ERROR";
-                       }
-                       break;
-               }
-
-               if (options.machinereadable) {
-                       printf("%s%s%s%s%s%i%s%s%s%lu.%06lu%s%lu.%06lu%s%s%s\n",
-                              options.sep,
-                              event_str, options.sep,
-                              slist->script[i].name, options.sep,
-                              slist->script[i].status, options.sep,
-                              status, options.sep,
-                              slist->script[i].start.tv_sec,
-                              slist->script[i].start.tv_usec, options.sep,
-                              slist->script[i].finished.tv_sec,
-                              slist->script[i].finished.tv_usec, options.sep,
-                              slist->script[i].output, options.sep);
-                       continue;
-               }
-
-               if (status) {
-                       printf("%-20s Status:%s    ",
-                              slist->script[i].name, status);
-               } else {
-                       /* Some other error, eg from stat. */
-                       printf("%-20s Status:CANNOT RUN (%s)",
-                              slist->script[i].name,
-                              strerror(-slist->script[i].status));
-               }
-
-               if (slist->script[i].status >= 0) {
-                       printf("Duration:%.3lf ",
-                              timeval_delta(&slist->script[i].finished,
-                                            &slist->script[i].start));
-               }
-               if (slist->script[i].status != -ENOEXEC) {
-                       printf("%s", ctime(&slist->script[i].start.tv_sec));
-                       if (slist->script[i].status != 0) {
-                               printf("   OUTPUT:%s\n",
-                                      slist->script[i].output);
-                       }
-               } else {
-                       printf("\n");
-               }
+       t = getenv("CTDB_EVENT_HELPER");
+       if (t != NULL) {
+               event_helper = talloc_strdup(mem_ctx, t);
+       } else {
+               event_helper = talloc_asprintf(mem_ctx, "%s/ctdb-event",
+                                              CTDB_HELPER_BINDIR);
        }
-}
 
-static void print_scriptstatus(struct ctdb_script_list **slist,
-                              int count, const char **event_str)
-{
-       int i;
-
-       if (options.machinereadable) {
-               printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-                      options.sep,
-                      "Type", options.sep,
-                      "Name", options.sep,
-                      "Code", options.sep,
-                      "Status", options.sep,
-                      "Start", options.sep,
-                      "End", options.sep,
-                      "Error Output", options.sep);
+       if (event_helper == NULL) {
+               fprintf(stderr, "Unable to set event daemon helper\n");
+               return 1;
        }
 
-       for (i=0; i<count; i++) {
-               print_scriptstatus_one(slist[i], event_str[i]);
-       }
+       return run_helper(mem_ctx, "event daemon helper", event_helper,
+                         argc, argv);
 }
 
 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                                int argc, const char **argv)
 {
-       struct ctdb_script_list **slist;
-       const char *event_str;
-       enum ctdb_event event;
-       const char *all_events[] = {
-               "init", "setup", "startup", "monitor",
-               "takeip", "releaseip", "updateip", "ipreallocated" };
-       bool valid;
-       int ret, i, j;
-       int count, start, end, num;
+       const char *new_argv[4];
 
        if (argc > 1) {
                usage("scriptstatus");
        }
 
-       if (argc == 0) {
-               event_str = "monitor";
-       } else {
-               event_str = argv[0];
-       }
-
-       valid = false;
-       for (i=0; i<ARRAY_SIZE(all_events); i++) {
-               if (strcmp(event_str, all_events[i]) == 0) {
-                       valid = true;
-                       count = 1;
-                       start = i;
-                       end = i+1;
-                       break;
-               }
-       }
-
-       if (strcmp(event_str, "all") == 0) {
-               valid = true;
-               count = ARRAY_SIZE(all_events);
-               start = 0;
-               end = count-1;
-       }
-
-       if (! valid) {
-               fprintf(stderr, "Unknown event name %s\n", argv[0]);
-               usage("scriptstatus");
-       }
-
-       slist = talloc_array(mem_ctx, struct ctdb_script_list *, count);
-       if (slist == NULL) {
-               fprintf(stderr, "Memory allocation error\n");
-               return 1;
-       }
-
-       num = 0;
-       for (i=start; i<end; i++) {
-               event = ctdb_event_from_string(all_events[i]);
-
-               ret = ctdb_ctrl_get_event_script_status(mem_ctx, ctdb->ev,
-                                                       ctdb->client,
-                                                       ctdb->cmd_pnn,
-                                                       TIMEOUT(), event,
-                                                       &slist[num]);
-               if (ret != 0) {
-                       fprintf(stderr,
-                               "failed to get script status for %s event\n",
-                               all_events[i]);
-                       return 1;
-               }
-
-               if (slist[num] == NULL) {
-                       num++;
-                       continue;
-               }
-
-               /* The ETIME status is ignored for certain events.
-                * In that case the status is 0, but endtime is not set.
-                */
-               for (j=0; j<slist[num]->num_scripts; j++) {
-                       if (slist[num]->script[j].status == 0 &&
-                           timeval_is_zero(&slist[num]->script[j].finished)) {
-                               slist[num]->script[j].status = -ETIME;
-                       }
-               }
-
-               num++;
-       }
-
-       print_scriptstatus(slist, count, &all_events[start]);
-       return 0;
-}
-
-static int control_enablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                               int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 1) {
-               usage("enablescript");
-       }
-
-       ret = ctdb_ctrl_enable_script(mem_ctx, ctdb->ev, ctdb->client,
-                                     ctdb->cmd_pnn, TIMEOUT(), argv[0]);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to enable script %s\n", argv[0]);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int control_disablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                                int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 1) {
-               usage("disablescript");
-       }
-
-       ret = ctdb_ctrl_disable_script(mem_ctx, ctdb->ev, ctdb->client,
-                                      ctdb->cmd_pnn, TIMEOUT(), argv[0]);
-       if (ret != 0) {
-               fprintf(stderr, "Failed to disable script %s\n", argv[0]);
-               return ret;
-       }
+       new_argv[0] = "status";
+       new_argv[1] = "legacy";
+       new_argv[2] = (argc == 0) ? "monitor" : argv[0];
+       new_argv[3] = NULL;
 
+       (void) control_event(mem_ctx, ctdb, 3, new_argv);
        return 0;
 }
 
@@ -4869,32 +4642,8 @@ static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       return run_helper("NAT gateway helper", natgw_helper, argv[0]);
-}
-
-static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                            int argc, const char **argv)
-{
-       char *t, *natgw_helper = NULL;
-
-       if (argc != 0) {
-               usage("natgwlist");
-       }
-
-       t = getenv("CTDB_NATGW_HELPER");
-       if (t != NULL) {
-               natgw_helper = talloc_strdup(mem_ctx, t);
-       } else {
-               natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
-                                              CTDB_HELPER_BINDIR);
-       }
-
-       if (natgw_helper == NULL) {
-               fprintf(stderr, "Unable to set NAT gateway helper\n");
-               return 1;
-       }
-
-       return run_helper("NAT gateway helper", natgw_helper, "natgwlist");
+       return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
+                         argc, argv);
 }
 
 /*
@@ -4905,7 +4654,7 @@ static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
 {
        struct ctdb_node_map *nodemap;
-       int i;
+       unsigned int i;
 
        nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
        if (nodemap == NULL) {
@@ -5026,8 +4775,8 @@ static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
                return 1;
        }
 
-       if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
-               fprintf(stderr, "Cannot set READONLY on persistent DB\n");
+       if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
+               fprintf(stderr, "READONLY can be set only on volatile DB\n");
                return 1;
        }
 
@@ -5055,8 +4804,8 @@ static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
-               fprintf(stderr, "Cannot set STICKY on persistent DB\n");
+       if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
+               fprintf(stderr, "STICKY can be set only on volatile DB\n");
                return 1;
        }
 
@@ -5079,7 +4828,7 @@ static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        TDB_DATA key, data;
        int ret;
 
-       if (argc < 2 || argc > 3) {
+       if (argc != 2) {
                usage("pfetch");
        }
 
@@ -5087,8 +4836,9 @@ static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
-               fprintf(stderr, "DB %s is not a persistent database\n",
+       if (! (db_flags &
+              (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
+               fprintf(stderr, "Transactions not supported on DB %s\n",
                        db_name);
                return 1;
        }
@@ -5118,6 +4868,7 @@ static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to read record for key %s\n",
                        argv[1]);
+               ctdb_transaction_cancel(h);
                return ret;
        }
 
@@ -5145,8 +4896,9 @@ static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
-               fprintf(stderr, "DB %s is not a persistent database\n",
+       if (! (db_flags &
+              (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
+               fprintf(stderr, "Transactions not supported on DB %s\n",
                        db_name);
                return 1;
        }
@@ -5182,6 +4934,7 @@ static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to store record for key %s\n",
                        argv[1]);
+               ctdb_transaction_cancel(h);
                return ret;
        }
 
@@ -5189,6 +4942,7 @@ static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to commit transaction on db %s\n",
                        db_name);
+               ctdb_transaction_cancel(h);
                return ret;
        }
 
@@ -5213,8 +4967,9 @@ static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
-               fprintf(stderr, "DB %s is not a persistent database\n",
+       if (! (db_flags &
+              (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
+               fprintf(stderr, "Transactions not supported on DB %s\n",
                        db_name);
                return 1;
        }
@@ -5244,6 +4999,7 @@ static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to delete record for key %s\n",
                        argv[1]);
+               ctdb_transaction_cancel(h);
                return ret;
        }
 
@@ -5251,6 +5007,7 @@ static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to commit transaction on db %s\n",
                        db_name);
+               ctdb_transaction_cancel(h);
                return ret;
        }
 
@@ -5335,7 +5092,7 @@ static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct ctdb_transaction_handle *h;
        uint8_t db_flags;
        FILE *file;
-       TDB_DATA key, value;
+       TDB_DATA key = tdb_null, value = tdb_null;
        int ret;
 
        if (argc < 1 || argc > 2) {
@@ -5346,8 +5103,9 @@ static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
-               fprintf(stderr, "DB %s is not a persistent database\n",
+       if (! (db_flags &
+              (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
+               fprintf(stderr, "Transactions not supported on DB %s\n",
                        db_name);
                return 1;
        }
@@ -5394,6 +5152,7 @@ static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        if (ret != 0) {
                fprintf(stderr, "Failed to commit transaction on db %s\n",
                        db_name);
+               ctdb_transaction_cancel(h);
        }
 
 done:
@@ -5424,17 +5183,20 @@ static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
        if (ret != 0) {
                fprintf(stderr, "Failed to parse key %s\n", argv[1]);
+               tdb_close(tdb);
                return ret;
        }
 
        data = tdb_fetch(tdb, key);
        if (data.dptr == NULL) {
                fprintf(stderr, "No record for key %s\n", argv[1]);
+               tdb_close(tdb);
                return 1;
        }
 
        if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
                fprintf(stderr, "Invalid record for key %s\n", argv[1]);
+               tdb_close(tdb);
                return 1;
        }
 
@@ -5452,7 +5214,8 @@ static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                }
 
                nwritten = sys_write(fd, data.dptr, data.dsize);
-               if (nwritten != data.dsize) {
+               if (nwritten == -1 ||
+                   (size_t)nwritten != data.dsize) {
                        fprintf(stderr, "Failed to write record to file\n");
                        close(fd);
                        goto fail;
@@ -5478,10 +5241,11 @@ static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                          int argc, const char **argv)
 {
        struct tdb_context *tdb;
-       TDB_DATA key, data, value;
+       TDB_DATA key, data[2], value;
        struct ctdb_ltdb_header header;
-       size_t offset;
-       int ret;
+       uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
+       size_t np;
+       int ret = 0;
 
        if (argc < 3 || argc > 5) {
                usage("tstore");
@@ -5496,19 +5260,28 @@ static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
        if (ret != 0) {
                fprintf(stderr, "Failed to parse key %s\n", argv[1]);
+               tdb_close(tdb);
                return ret;
        }
 
        ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
        if (ret != 0) {
                fprintf(stderr, "Failed to parse value %s\n", argv[2]);
+               tdb_close(tdb);
                return ret;
        }
 
        ZERO_STRUCT(header);
 
        if (argc > 3) {
-               header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
+               header.rsn = (uint64_t)smb_strtoull(argv[3],
+                                                   NULL,
+                                                   0,
+                                                   &ret,
+                                                   SMB_STR_STANDARD);
+               if (ret != 0) {
+                       return ret;
+               }
        }
        if (argc > 4) {
                header.dmaster = (uint32_t)atol(argv[4]);
@@ -5517,18 +5290,15 @@ static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                header.flags = (uint32_t)atol(argv[5]);
        }
 
-       offset = ctdb_ltdb_header_len(&header);
-       data.dsize = offset + value.dsize;
-       data.dptr = talloc_size(mem_ctx, data.dsize);
-       if (data.dptr == NULL) {
-               fprintf(stderr, "Memory allocation error\n");
-               return 1;
-       }
+       ctdb_ltdb_header_push(&header, header_buf, &np);
+
+       data[0].dsize = np;
+       data[0].dptr = header_buf;
 
-       ctdb_ltdb_header_push(&header, data.dptr);
-       memcpy(data.dptr + offset, value.dptr, value.dsize);
+       data[1].dsize = value.dsize;
+       data[1].dptr = value.dptr;
 
-       ret = tdb_store(tdb, key, data, TDB_REPLACE);
+       ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
        if (ret != 0) {
                fprintf(stderr, "Failed to write record %s to file %s\n",
                        argv[1], argv[0]);
@@ -5566,7 +5336,7 @@ static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
+       if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
                fprintf(stderr, "DB %s is not a volatile database\n",
                        db_name);
                return 1;
@@ -5617,7 +5387,7 @@ static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
+       if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
                fprintf(stderr, "DB %s is not a volatile database\n",
                        db_name);
                return 1;
@@ -5677,7 +5447,7 @@ static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                return 1;
        }
 
-       if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
+       if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
                fprintf(stderr, "DB %s is not a volatile database\n",
                        db_name);
                return 1;
@@ -5737,6 +5507,7 @@ static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        v = fcntl(s, F_GETFL, 0);
        if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
                fprintf(stderr, "Unable to set socket non-blocking\n");
+               close(s);
                return errno;
        }
 
@@ -5753,22 +5524,6 @@ static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return 0;
 }
 
-static int control_rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                                int argc, const char **argv)
-{
-       if (argc != 0) {
-               usage("rebalancenode");
-       }
-
-       if (! rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn)) {
-               fprintf(stderr, "Failed to rebalance IPs on node %u\n",
-                       ctdb->cmd_pnn);
-               return 1;
-       }
-
-       return 0;
-}
-
 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                               int argc, const char **argv)
 {
@@ -5803,7 +5558,9 @@ static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        const char *nodestring = NULL;
        struct ctdb_node_map *nodemap;
-       int ret, i;
+       unsigned int i;
+       int ret;
+       bool print_hdr = false;
 
        if (argc > 1) {
                usage("nodestatus");
@@ -5811,26 +5568,30 @@ static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
        if (argc == 1) {
                nodestring = argv[0];
+               if (strcmp(nodestring, "all") == 0) {
+                       print_hdr = true;
+               }
        }
 
        if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
                return 1;
        }
 
-       nodemap = get_nodemap(ctdb, false);
-       if (nodemap == NULL) {
-               return 1;
-       }
-
        if (options.machinereadable) {
                print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
        } else {
-               print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
+               print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
        }
 
        ret = 0;
        for (i=0; i<nodemap->num; i++) {
-               ret |= nodemap->node[i].flags;
+               uint32_t flags = nodemap->node[i].flags;
+
+               if ((flags & NODE_FLAGS_DELETED) != 0) {
+                       continue;
+               }
+
+               ret |= flags;
        }
 
        return ret;
@@ -5847,13 +5608,12 @@ const struct {
        DBSTATISTICS_FIELD(locks.num_current),
        DBSTATISTICS_FIELD(locks.num_pending),
        DBSTATISTICS_FIELD(locks.num_failed),
-       DBSTATISTICS_FIELD(db_ro_delegations),
 };
 
 static void print_dbstatistics(const char *db_name,
                               struct ctdb_db_statistics *s)
 {
-       int i;
+       size_t i;
        const char *prefix = NULL;
        int preflen = 0;
 
@@ -5900,7 +5660,7 @@ static void print_dbstatistics(const char *db_name,
 
        printf(" Num Hot Keys:     %d\n", s->num_hot_keys);
        for (i=0; i<s->num_hot_keys; i++) {
-               int j;
+               size_t j;
                printf("     Count:%d Key:", s->hot_keys[i].count);
                for (j=0; j<s->hot_keys[i].key.dsize; j++) {
                        printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
@@ -5940,7 +5700,7 @@ static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 
 struct disable_takeover_runs_state {
        uint32_t *pnn_list;
-       int node_count;
+       unsigned int node_count;
        bool *reply;
        int status;
        bool done;
@@ -5951,7 +5711,8 @@ static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
 {
        struct disable_takeover_runs_state *state =
                (struct disable_takeover_runs_state *)private_data;
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        if (data.dsize != sizeof(int)) {
                /* Ignore packet */
@@ -5966,7 +5727,7 @@ static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
                return;
        }
        for (i=0; i<state->node_count; i++) {
-               if (state->pnn_list[i] == ret) {
+               if (state->pnn_list[i] == (uint32_t)ret) {
                        state->reply[i] = true;
                        break;
                }
@@ -6112,32 +5873,6 @@ static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        return ipreallocate(mem_ctx, ctdb);
 }
 
-static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
-                          int argc, const char **argv)
-{
-       ctdb_sock_addr addr;
-       char *iface;
-
-       if (argc != 1) {
-               usage("ipiface");
-       }
-
-       if (! parse_ip(argv[0], NULL, 0, &addr)) {
-               fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
-               return 1;
-       }
-
-       iface = ctdb_sys_find_ifname(&addr);
-       if (iface == NULL) {
-               fprintf(stderr, "Failed to find interface for IP %s\n",
-                       argv[0]);
-               return 1;
-       }
-       free(iface);
-
-       return 0;
-}
-
 
 static const struct ctdb_cmd {
        const char *name;
@@ -6154,7 +5889,7 @@ static const struct ctdb_cmd {
        { "uptime", control_uptime, false, true,
                "show node uptime", NULL },
        { "ping", control_ping, false, true,
-               "ping all nodes", NULL },
+               "ping a node", NULL },
        { "runstate", control_runstate, false, true,
                "get/check runstate of a node",
                "[setup|first_recovery|startup|running]" },
@@ -6179,7 +5914,7 @@ static const struct ctdb_cmd {
        { "setifacelink", control_setifacelink, false, true,
                "set interface link status", "<iface> up|down" },
        { "process-exists", control_process_exists, false, true,
-               "check if a process exists on a node",  "<pid>" },
+               "check if a process exists on a node",  "<pid> [<srvid>]" },
        { "getdbmap", control_getdbmap, false, true,
                "show attached databases", NULL },
        { "getdbstatus", control_getdbstatus, false, true,
@@ -6188,24 +5923,18 @@ static const struct ctdb_cmd {
                "dump cluster-wide ctdb database", "<dbname|dbid>" },
        { "cattdb", control_cattdb, false, false,
                "dump local ctdb database", "<dbname|dbid>" },
-       { "getmonmode", control_getmonmode, false, true,
-               "show monitoring mode", NULL },
        { "getcapabilities", control_getcapabilities, false, true,
                "show node capabilities", NULL },
        { "pnn", control_pnn, false, false,
                "show the pnn of the currnet node", NULL },
        { "lvs", control_lvs, false, false,
-               "show lvs configuration", "master|list|status" },
-       { "disablemonitor", control_disable_monitor, false, true,
-               "disable monitoring", NULL },
-       { "enablemonitor", control_enable_monitor, false, true,
-               "enable monitoring", NULL },
+               "show lvs configuration", "leader|list|status" },
        { "setdebug", control_setdebug, false, true,
                "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
        { "getdebug", control_getdebug, false, true,
                "get debug level", NULL },
        { "attach", control_attach, false, false,
-               "attach a database", "<dbname> [persistent]" },
+               "attach a database", "<dbname> [persistent|replicated]" },
        { "detach", control_detach, false, false,
                "detach database(s)", "<dbname|dbid> ..." },
        { "dumpmemory", control_dumpmemory, false, true,
@@ -6234,11 +5963,9 @@ static const struct ctdb_cmd {
                "run ip reallocation (deprecated)", NULL },
        { "ipreallocate", control_ipreallocate, false, true,
                "run ip reallocation", NULL },
-       { "isnotrecmaster", control_isnotrecmaster, false, false,
-               "check if local node is the recmaster", NULL },
        { "gratarp", control_gratarp, false, true,
                "send a gratuitous arp", "<ip> <interface>" },
-       { "tickle", control_tickle, false, false,
+       { "tickle", control_tickle, true, false,
                "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
        { "gettickles", control_gettickles, false, true,
                "get the list of tickles", "<ip> [<port>]" },
@@ -6246,22 +5973,16 @@ static const struct ctdb_cmd {
                "add a tickle", "<ip>:<port> <ip>:<port>" },
        { "deltickle", control_deltickle, false, true,
                "delete a tickle", "<ip>:<port> <ip>:<port>" },
-       { "check_srvids", control_check_srvids, false, true,
-               "check if srvid is registered", "<id> [<id> ...]" },
        { "listnodes", control_listnodes, true, true,
                "list nodes in the cluster", NULL },
        { "reloadnodes", control_reloadnodes, false, false,
                "reload the nodes file all nodes", NULL },
        { "moveip", control_moveip, false, false,
                "move an ip address to another node", "<ip> <node>" },
-       { "rebalanceip", control_rebalanceip, false, false,
-               "move an ip address optimally to another node", "<ip>" },
        { "addip", control_addip, false, true,
                "add an ip address to a node", "<ip/mask> <iface>" },
        { "delip", control_delip, false, true,
                "delete an ip address from a node", "<ip>" },
-       { "eventscript", control_eventscript, false, true,
-               "run an event", "monitor" },
        { "backupdb", control_backupdb, false, false,
                "backup a database into a file", "<dbname|dbid> <file>" },
        { "restoredb", control_restoredb, false, false,
@@ -6272,17 +5993,13 @@ static const struct ctdb_cmd {
                "wipe the contents of a database.", "<dbname|dbid>"},
        { "recmaster", control_recmaster, false, true,
                "show the pnn for the recovery master", NULL },
-       { "scriptstatus", control_scriptstatus, false, true,
+       { "event", control_event, true, false,
+               "event and event script commands", NULL },
+       { "scriptstatus", control_scriptstatus, true, false,
                "show event script status",
                "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
-       { "enablescript", control_enablescript, false, true,
-               "enable an eventscript", "<script>"},
-       { "disablescript", control_disablescript, false, true,
-               "disable an eventscript", "<script>"},
        { "natgw", control_natgw, false, false,
-               "show natgw configuration", "master|list|status" },
-       { "natgwlist", control_natgwlist, false, false,
-               "show the nodes belonging to this natgw configuration", NULL },
+               "show natgw configuration", "leader|list|status" },
        { "getreclock", control_getreclock, false, true,
                "get recovery lock file", NULL },
        { "setlmasterrole", control_setlmasterrole, false, true,
@@ -6294,7 +6011,7 @@ static const struct ctdb_cmd {
        { "setdbsticky", control_setdbsticky, false, true,
                "enable sticky records", "<dbname|dbid>"},
        { "pfetch", control_pfetch, false, false,
-               "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
+               "fetch record from persistent database", "<dbname|dbid> <key>" },
        { "pstore", control_pstore, false, false,
                "write record to persistent database", "<dbname|dbid> <key> <value>" },
        { "pdelete", control_pdelete, false, false,
@@ -6313,8 +6030,6 @@ static const struct ctdb_cmd {
                "delete a database key", "<dbname|dbid> <key>" },
        { "checktcpport", control_checktcpport, true, false,
                "check if a service is bound to a specific tcp port or not", "<port>" },
-       { "rebalancenode", control_rebalancenode, false, true,
-               "mark nodes as forced IP rebalancing targets", NULL },
        { "getdbseqnum", control_getdbseqnum, false, false,
                "get database sequence number", "<dbname|dbid>" },
        { "nodestatus", control_nodestatus, false, true,
@@ -6323,14 +6038,12 @@ static const struct ctdb_cmd {
                "show database statistics", "<dbname|dbid>" },
        { "reloadips", control_reloadips, false, false,
                "reload the public addresses file", "[all|<pnn-list>]" },
-       { "ipiface", control_ipiface, true, false,
-               "Find the interface an ip address is hosted on", "<ip>" },
 };
 
 static const struct ctdb_cmd *match_command(const char *command)
 {
        const struct ctdb_cmd *cmd;
-       int i;
+       size_t i;
 
        for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
                cmd = &ctdb_commands[i];
@@ -6349,7 +6062,7 @@ static const struct ctdb_cmd *match_command(const char *command)
  */
 static void usage_full(void)
 {
-       int i;
+       size_t i;
 
        poptPrintHelp(pc, stdout, 0);
        printf("\nCommands:\n");
@@ -6385,24 +6098,70 @@ static void usage(const char *command)
 
 struct poptOption cmdline_options[] = {
        POPT_AUTOHELP
-       { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
-               "CTDB socket path", "filename" },
-       { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
-               "debug level"},
-       { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
-               "timelimit (in seconds)" },
-       { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
-               "node specification - integer" },
-       { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
-               "enable machine readable output", NULL },
-       { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
-               "specify separator for machine readable output", "CHAR" },
-       { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
-               "enable machine parsable output with separator |", NULL },
-       { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
-               "enable verbose output", NULL },
-       { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
-               "die if runtime exceeds this limit (in seconds)" },
+       {
+               .longName   = "debug",
+               .shortName  = 'd',
+               .argInfo    = POPT_ARG_STRING,
+               .arg        = &options.debuglevelstr,
+               .val        = 0,
+               .descrip    = "debug level",
+       },
+       {
+               .longName   = "timelimit",
+               .shortName  = 't',
+               .argInfo    = POPT_ARG_INT,
+               .arg        = &options.timelimit,
+               .val        = 0,
+               .descrip    = "timelimit (in seconds)",
+       },
+       {
+               .longName   = "node",
+               .shortName  = 'n',
+               .argInfo    = POPT_ARG_INT,
+               .arg        = &options.pnn,
+               .val        = 0,
+               .descrip    = "node specification - integer",
+       },
+       {
+               .longName   = NULL,
+               .shortName  = 'Y',
+               .argInfo    = POPT_ARG_NONE,
+               .arg        = &options.machinereadable,
+               .val        = 0,
+               .descrip    = "enable machine readable output",
+       },
+       {
+               .longName   = "separator",
+               .shortName  = 'x',
+               .argInfo    = POPT_ARG_STRING,
+               .arg        = &options.sep,
+               .val        = 0,
+               .descrip    = "specify separator for machine readable output",
+               .argDescrip = "CHAR",
+       },
+       {
+               .shortName  = 'X',
+               .argInfo    = POPT_ARG_NONE,
+               .arg        = &options.machineparsable,
+               .val        = 0,
+               .descrip    = "enable machine parsable output with separator |",
+       },
+       {
+               .longName   = "verbose",
+               .shortName  = 'v',
+               .argInfo    = POPT_ARG_NONE,
+               .arg        = &options.verbose,
+               .val        = 0,
+               .descrip    = "enable verbose output",
+       },
+       {
+               .longName   = "maxruntime",
+               .shortName  = 'T',
+               .argInfo    = POPT_ARG_INT,
+               .arg        = &options.maxruntime,
+               .val        = 0,
+               .descrip    = "die if runtime exceeds this limit (in seconds)",
+       },
        POPT_TABLEEND
 };
 
@@ -6411,6 +6170,7 @@ static int process_command(const struct ctdb_cmd *cmd, int argc,
 {
        TALLOC_CTX *tmp_ctx;
        struct ctdb_context *ctdb;
+       const char *ctdb_socket;
        int ret;
        bool status;
        uint64_t srvid_offset;
@@ -6429,7 +6189,9 @@ static int process_command(const struct ctdb_cmd *cmd, int argc,
                        goto fail;
                }
 
-               return cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
+               ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
+               talloc_free(tmp_ctx);
+               return ret;
        }
 
        ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
@@ -6444,10 +6206,16 @@ static int process_command(const struct ctdb_cmd *cmd, int argc,
                goto fail;
        }
 
-       ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
+       ctdb_socket = path_socket(ctdb, "ctdbd");
+       if (ctdb_socket == NULL) {
+               fprintf(stderr, "Memory allocation error\n");
+               goto fail;
+       }
+
+       ret = ctdb_client_init(ctdb, ctdb->ev, ctdb_socket, &ctdb->client);
        if (ret != 0) {
                fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
-                       options.socket);
+                       ctdb_socket);
 
                if (!find_node_xpnn(ctdb, NULL)) {
                        fprintf(stderr, "Is this node part of CTDB cluster?\n");
@@ -6505,25 +6273,20 @@ int main(int argc, const char *argv[])
        const char **extra_argv;
        int extra_argc;
        const struct ctdb_cmd *cmd;
-       const char *ctdb_socket;
-       enum debug_level loglevel;
-       int ret;
+       const char *test_mode;
+       int loglevel;
+       bool ok;
+       int ret = 0;
 
        setlinebuf(stdout);
 
        /* Set default options */
-       options.socket = CTDB_SOCKET;
        options.debuglevelstr = NULL;
        options.timelimit = 10;
        options.sep = "|";
        options.maxruntime = 0;
        options.pnn = -1;
 
-       ctdb_socket = getenv("CTDB_SOCKET");
-       if (ctdb_socket != NULL) {
-               options.socket = ctdb_socket;
-       }
-
        pc = poptGetContext(argv[0], argc, argv, cmdline_options,
                            POPT_CONTEXT_KEEP_FIRST);
        while ((opt = poptGetNextOpt(pc)) != -1) {
@@ -6537,15 +6300,19 @@ int main(int argc, const char *argv[])
 
                ctdb_timeout = getenv("CTDB_TIMEOUT");
                if (ctdb_timeout != NULL) {
-                       options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
+                       options.maxruntime = smb_strtoul(ctdb_timeout,
+                                                        NULL,
+                                                        0,
+                                                        &ret,
+                                                        SMB_STR_STANDARD);
+                       if (ret != 0) {
+                               fprintf(stderr, "Invalid value CTDB_TIMEOUT\n");
+                               exit(1);
+                       }
                } else {
                        options.maxruntime = 120;
                }
        }
-       if (options.maxruntime <= 120) {
-               /* default timeout is 120 seconds */
-               options.maxruntime = 120;
-       }
 
        if (options.machineparsable) {
                options.machinereadable = 1;
@@ -6571,10 +6338,20 @@ int main(int argc, const char *argv[])
 
        /* Enable logging */
        setup_logging("ctdb", DEBUG_STDERR);
-       if (debug_level_parse(options.debuglevelstr, &loglevel)) {
-               DEBUGLEVEL = loglevel;
-       } else {
-               DEBUGLEVEL = DEBUG_ERR;
+       ok = debug_level_parse(options.debuglevelstr, &loglevel);
+       if (!ok) {
+               loglevel = DEBUG_ERR;
+       }
+       debuglevel_set(loglevel);
+
+       /* Stop process group kill in alarm_handler() from killing tests */
+       test_mode = getenv("CTDB_TEST_MODE");
+       if (test_mode != NULL) {
+               const char *have_setpgid = getenv("CTDB_TOOL_SETPGID");
+               if (have_setpgid == NULL) {
+                       setpgid(0, 0);
+                       setenv("CTDB_TOOL_SETPGID", "1", 1);
+               }
        }
 
        signal(SIGALRM, alarm_handler);