ctdb: Remove <file> parameter from pfetch usage info
[amitay/samba.git] / ctdb / tools / ctdb.c
index 2cb699aadf2c4cdc21de08deda786be636d72725..b598a866c9bd3ab6c090182608e33310fcffe09d 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 "common/version.h"
 #include "lib/util/debug.h"
 #include "lib/util/samba_util.h"
+#include "lib/util/sys_rw.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 +51,6 @@
 #define SRVID_CTDB_PUSHDB  (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
 
 static struct {
-       const char *socket;
        const char *debuglevelstr;
        int timelimit;
        int pnn;
@@ -378,8 +382,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 +478,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);
-               }
-       }
-       if (nodes_list == NULL) {
-               nodes_list = getenv("CTDB_NODES");
+       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) {
-               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);
@@ -593,7 +587,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';
 }
@@ -644,28 +638,45 @@ static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
        return ret;
 }
 
-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 +686,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 +715,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", ctdb_version_string);
        return 0;
 }
 
@@ -758,7 +778,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,7 +794,8 @@ 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;
@@ -786,11 +807,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 +825,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),
@@ -816,7 +840,7 @@ static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
 {
        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");
@@ -1124,9 +1148,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),
@@ -1374,6 +1400,14 @@ 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,
@@ -1402,18 +1436,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 +1462,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 +1474,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 +1489,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 : "");
                }
        }
@@ -1510,7 +1550,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 +1562,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;
+                                       }
+                               }
                        }
                }
 
@@ -1592,12 +1656,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 +1678,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,
@@ -1634,7 +1706,8 @@ static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                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 +1724,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++) {
@@ -1785,23 +1858,43 @@ static int control_process_exists(TALLOC_CTX *mem_ctx,
                                  int argc, const char **argv)
 {
        pid_t pid;
+       uint64_t srvid = 0;
        int ret, status;
 
-       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 = strtoull(argv[1], NULL, 0);
+       }
+
+       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;
 }
@@ -1823,7 +1916,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 +1924,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 +1937,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 +1966,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 +1977,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 +2028,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;
 }
 
@@ -2005,51 +2104,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) {
-               talloc_free(rec);
-               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)
 {
@@ -2057,8 +2111,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) {
@@ -2076,44 +2129,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,
@@ -2142,33 +2166,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)
@@ -2233,51 +2237,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;
 
@@ -2306,7 +2272,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;
 
@@ -2345,6 +2311,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");
                }
@@ -2432,15 +2400,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;
@@ -2577,6 +2544,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;
@@ -2820,15 +2821,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) {
@@ -2836,6 +2851,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;
 }
 
@@ -2976,7 +2995,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;
        }
@@ -3005,19 +3025,20 @@ 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;
+               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;
@@ -3036,12 +3057,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;
        }
@@ -3071,10 +3094,12 @@ static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                port = strtoul(argv[1], NULL, 10);
        }
 
-       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,
@@ -3094,28 +3119,27 @@ 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));
                }
        }
 
@@ -3129,7 +3153,7 @@ 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;
        clist_reply_func reply_func;
@@ -3140,8 +3164,7 @@ 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)
 {
@@ -3156,11 +3179,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);
@@ -3198,7 +3220,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);
        }
 }
@@ -3222,19 +3244,19 @@ 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 (count == 0) {
+               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) {
@@ -3254,11 +3276,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;
        }
@@ -3285,19 +3309,19 @@ 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 (count == 0) {
+               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) {
@@ -3317,11 +3341,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;
        }
@@ -3336,44 +3362,6 @@ 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)
 {
@@ -3398,12 +3386,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));
                }
        }
 
@@ -3451,7 +3439,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;
                }
@@ -3471,9 +3459,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) {
@@ -3737,7 +3727,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);
@@ -3752,7 +3742,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;
        }
 
@@ -3800,7 +3790,8 @@ static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                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;
        }
@@ -3830,59 +3821,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)
 {
@@ -3912,13 +3850,15 @@ static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                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);
@@ -3928,7 +3868,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;
                }
        }
@@ -3960,7 +3901,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,
@@ -3975,13 +3916,15 @@ static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
                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);
@@ -3996,7 +3939,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;
        }
 
@@ -4015,31 +3958,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)
@@ -4150,7 +4068,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);
@@ -4208,8 +4126,10 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        uint32_t generation;
        uint32_t *pnn_list;
        char timebuf[128];
+       ssize_t n;
        int fd, i;
        int count, ret;
+       uint8_t db_flags;
 
        if (argc < 1 || argc > 2) {
                usage("restoredb");
@@ -4227,14 +4147,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,
@@ -4252,10 +4173,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;
        }
 
@@ -4323,6 +4246,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) {
@@ -4335,7 +4259,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;
@@ -4403,6 +4327,7 @@ static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        }
 
        printf("Database %s restored\n", db_name);
+       close(fd);
        return 0;
 
 
@@ -4442,6 +4367,7 @@ static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        struct db_header db_hdr;
        char timebuf[128];
        struct dumpdbbackup_state state;
+       ssize_t n;
        int fd, ret, i;
 
        if (argc != 1) {
@@ -4456,14 +4382,15 @@ 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,
@@ -4629,241 +4556,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;
-
-       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;
-               }
+       char *t, *event_helper = NULL;
 
-               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;
-       end = 0;
-
-       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;
 }
 
@@ -4889,32 +4618,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);
 }
 
 /*
@@ -5046,8 +4751,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;
        }
 
@@ -5075,8 +4780,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;
        }
 
@@ -5099,7 +4804,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");
        }
 
@@ -5107,8 +4812,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;
        }
@@ -5166,8 +4872,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;
        }
@@ -5236,8 +4943,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;
        }
@@ -5371,8 +5079,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;
        }
@@ -5507,9 +5216,10 @@ 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;
+       uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
+       size_t np;
        int ret;
 
        if (argc < 3 || argc > 5) {
@@ -5548,19 +5258,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");
-               tdb_close(tdb);
-               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]);
@@ -5598,7 +5304,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;
@@ -5649,7 +5355,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;
@@ -5709,7 +5415,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;
@@ -5786,22 +5492,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)
 {
@@ -5837,6 +5527,7 @@ static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
        const char *nodestring = NULL;
        struct ctdb_node_map *nodemap;
        int ret, i;
+       bool print_hdr = false;
 
        if (argc > 1) {
                usage("nodestatus");
@@ -5844,21 +5535,19 @@ 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;
@@ -5880,7 +5569,6 @@ 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,
@@ -6145,32 +5833,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;
@@ -6187,7 +5849,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]" },
@@ -6212,7 +5874,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,
@@ -6221,24 +5883,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 },
        { "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,
@@ -6279,22 +5935,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,
@@ -6305,17 +5955,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 },
        { "getreclock", control_getreclock, false, true,
                "get recovery lock file", NULL },
        { "setlmasterrole", control_setlmasterrole, false, true,
@@ -6327,7 +5973,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,
@@ -6346,8 +5992,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,
@@ -6356,8 +6000,6 @@ 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)
@@ -6418,8 +6060,6 @@ 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,
@@ -6444,6 +6084,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;
@@ -6479,10 +6120,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");
@@ -6540,25 +6187,19 @@ 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 loglevel;
+       bool ok;
        int ret;
 
        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) {
@@ -6606,11 +6247,11 @@ 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);
 
        signal(SIGALRM, alarm_handler);
        alarm(options.maxruntime);