4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
33 #include "ctdb_version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
38 #include "common/db_hash.h"
39 #include "common/logging.h"
40 #include "protocol/protocol.h"
41 #include "protocol/protocol_api.h"
42 #include "common/system.h"
43 #include "client/client.h"
44 #include "client/client_sync.h"
46 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
48 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
49 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
53 const char *debuglevelstr;
61 int printemptyrecords;
68 static poptContext pc;
71 struct tevent_context *ev;
72 struct ctdb_client_context *client;
73 struct ctdb_node_map *nodemap;
74 uint32_t pnn, cmd_pnn;
78 static void usage(const char *command);
84 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
86 return (tv2->tv_sec - tv->tv_sec) +
87 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
90 static struct ctdb_node_and_flags *get_node_by_pnn(
91 struct ctdb_node_map *nodemap,
96 for (i=0; i<nodemap->num; i++) {
97 if (nodemap->node[i].pnn == pnn) {
98 return &nodemap->node[i];
104 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
106 static const struct {
110 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
111 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
112 { NODE_FLAGS_BANNED, "BANNED" },
113 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
114 { NODE_FLAGS_DELETED, "DELETED" },
115 { NODE_FLAGS_STOPPED, "STOPPED" },
116 { NODE_FLAGS_INACTIVE, "INACTIVE" },
118 char *flags_str = NULL;
121 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
122 if (flags & flag_names[i].flag) {
123 if (flags_str == NULL) {
124 flags_str = talloc_asprintf(mem_ctx,
125 "%s", flag_names[i].name);
127 flags_str = talloc_asprintf_append(flags_str,
128 "|%s", flag_names[i].name);
130 if (flags_str == NULL) {
131 return "OUT-OF-MEMORY";
135 if (flags_str == NULL) {
142 static uint64_t next_srvid(struct ctdb_context *ctdb)
149 * Get consistent nodemap information.
151 * If nodemap is already cached, use that. If not get it.
152 * If the current node is BANNED, then get nodemap from "better" node.
154 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
157 struct ctdb_node_map *nodemap;
158 struct ctdb_node_and_flags *node;
159 uint32_t current_node;
163 TALLOC_FREE(ctdb->nodemap);
166 if (ctdb->nodemap != NULL) {
167 return ctdb->nodemap;
170 tmp_ctx = talloc_new(ctdb);
171 if (tmp_ctx == NULL) {
175 current_node = ctdb->pnn;
177 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
178 current_node, TIMEOUT(), &nodemap);
180 fprintf(stderr, "Failed to get nodemap from node %u\n",
185 node = get_node_by_pnn(nodemap, current_node);
186 if (node->flags & NODE_FLAGS_BANNED) {
189 current_node = (current_node + 1) % nodemap->num;
190 node = get_node_by_pnn(nodemap, current_node);
192 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
195 } while (current_node != ctdb->pnn);
197 if (current_node == ctdb->pnn) {
198 /* Tried all nodes in the cluster */
199 fprintf(stderr, "Warning: All nodes are banned.\n");
206 ctdb->nodemap = talloc_steal(ctdb, nodemap);
210 talloc_free(tmp_ctx);
214 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
216 struct ctdb_node_map *nodemap;
224 nodemap = get_nodemap(ctdb, false);
225 if (nodemap == NULL) {
230 for (i=0; i<nodemap->num; i++) {
231 if (nodemap->node[i].pnn == pnn) {
237 fprintf(stderr, "Node %u does not exist\n", pnn);
241 if (nodemap->node[i].flags &
242 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
243 fprintf(stderr, "Node %u has status %s\n", pnn,
244 pretty_print_flags(ctdb, nodemap->node[i].flags));
251 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
252 struct ctdb_node_map *nodemap)
254 struct ctdb_node_map *nodemap2;
256 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
257 if (nodemap2 == NULL) {
261 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
263 if (nodemap2->node == NULL) {
264 talloc_free(nodemap2);
272 * Get the number and the list of matching nodes
274 * nodestring := NULL | all | pnn,[pnn,...]
276 * If nodestring is NULL, use the current node.
278 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
279 const char *nodestring,
280 struct ctdb_node_map **out)
282 struct ctdb_node_map *nodemap, *nodemap2;
283 struct ctdb_node_and_flags *node;
286 nodemap = get_nodemap(ctdb, false);
287 if (nodemap == NULL) {
291 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
292 if (nodemap2 == NULL) {
296 if (nodestring == NULL) {
297 for (i=0; i<nodemap->num; i++) {
298 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
299 nodemap2->node[0] = nodemap->node[i];
308 if (strcmp(nodestring, "all") == 0) {
309 for (i=0; i<nodemap->num; i++) {
310 nodemap2->node[i] = nodemap->node[i];
312 nodemap2->num = nodemap->num;
318 ns = talloc_strdup(mem_ctx, nodestring);
323 tok = strtok(ns, ",");
324 while (tok != NULL) {
328 pnn = (uint32_t)strtoul(tok, &endptr, 0);
329 if (pnn == 0 && tok == endptr) {
330 fprintf(stderr, "Invalid node %s\n", tok);
334 node = get_node_by_pnn(nodemap, pnn);
336 fprintf(stderr, "Node %u does not exist\n",
341 nodemap2->node[nodemap2->num] = *node;
344 tok = strtok(NULL, ",");
353 /* Compare IP address */
354 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
358 if (ip1->sa.sa_family != ip2->sa.sa_family) {
362 switch (ip1->sa.sa_family) {
364 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
365 sizeof(struct in_addr)) == 0);
369 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
370 sizeof(struct in6_addr)) == 0);
377 /* Append a node to a node map with given address and flags */
378 static bool node_map_add(struct ctdb_node_map *nodemap,
379 const char *nstr, uint32_t flags)
383 struct ctdb_node_and_flags *n;
385 if (! parse_ip(nstr, NULL, 0, &addr)) {
386 fprintf(stderr, "Invalid IP address %s\n", nstr);
391 nodemap->node = talloc_realloc(nodemap, nodemap->node,
392 struct ctdb_node_and_flags, num+1);
393 if (nodemap->node == NULL) {
397 n = &nodemap->node[num];
402 nodemap->num = num+1;
406 /* Read a nodes file into a node map */
407 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
413 struct ctdb_node_map *nodemap;
415 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
416 if (nodemap == NULL) {
420 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
425 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
429 for (i=0; i<nlines; i++) {
435 /* strip leading spaces */
436 while((*node == ' ') || (*node == '\t')) {
442 /* strip trailing spaces */
444 ((node[len-1] == ' ') || (node[len-1] == '\t')))
454 /* A "deleted" node is a node that is
455 commented out in the nodes file. This is
456 used instead of removing a line, which
457 would cause subsequent nodes to change
459 flags = NODE_FLAGS_DELETED;
460 node = discard_const("0.0.0.0");
464 if (! node_map_add(nodemap, node, flags)) {
466 TALLOC_FREE(nodemap);
475 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
477 struct ctdb_node_map *nodemap;
479 const char *nodes_list = NULL;
481 if (pnn != CTDB_UNKNOWN_PNN) {
482 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
483 if (nodepath != NULL) {
484 nodes_list = getenv(nodepath);
487 if (nodes_list == NULL) {
488 nodes_list = getenv("CTDB_NODES");
490 if (nodes_list == NULL) {
491 const char *basedir = getenv("CTDB_BASE");
492 if (basedir == NULL) {
493 basedir = CTDB_ETCDIR;
495 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
496 if (nodes_list == NULL) {
497 fprintf(stderr, "Memory allocation error\n");
502 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
503 if (nodemap == NULL) {
504 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
512 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
513 struct ctdb_context *ctdb,
514 struct ctdb_dbid_map *dbmap,
517 struct ctdb_dbid *db = NULL;
521 for (i=0; i<dbmap->num; i++) {
522 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
523 ctdb->pnn, TIMEOUT(),
524 dbmap->dbs[i].db_id, &name);
529 if (strcmp(db_name, name) == 0) {
530 talloc_free(discard_const(name));
539 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
540 const char *db_arg, uint32_t *db_id,
541 const char **db_name, uint8_t *db_flags)
543 struct ctdb_dbid_map *dbmap;
544 struct ctdb_dbid *db = NULL;
546 const char *name = NULL;
549 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
550 ctdb->pnn, TIMEOUT(), &dbmap);
555 if (strncmp(db_arg, "0x", 2) == 0) {
556 id = strtoul(db_arg, NULL, 0);
557 for (i=0; i<dbmap->num; i++) {
558 if (id == dbmap->dbs[i].db_id) {
565 db = db_find(mem_ctx, ctdb, dbmap, name);
569 fprintf(stderr, "No database matching '%s' found\n", db_arg);
574 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
575 ctdb->pnn, TIMEOUT(), id, &name);
584 if (db_name != NULL) {
585 *db_name = talloc_strdup(mem_ctx, name);
587 if (db_flags != NULL) {
588 *db_flags = db->flags;
593 static int h2i(char h)
595 if (h >= 'a' && h <= 'f') {
598 if (h >= 'A' && h <= 'F') {
604 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
611 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
616 data.dsize = len / 2;
617 data.dptr = talloc_size(mem_ctx, data.dsize);
618 if (data.dptr == NULL) {
622 for (i=0; i<data.dsize; i++) {
623 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
630 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
636 if (strncmp(str, "0x", 2) == 0) {
637 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
639 data.dptr = talloc_memdup(mem_ctx, str, len);
640 if (data.dptr == NULL) {
650 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
651 const char *path, int argc, const char **argv)
654 int save_errno, status, ret;
655 const char **new_argv;
658 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
659 if (new_argv == NULL) {
664 for (i=0; i<argc; i++) {
665 new_argv[i+1] = argv[i];
667 new_argv[argc+1] = NULL;
672 talloc_free(new_argv);
673 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
674 command, path, strerror(save_errno));
679 ret = execv(path, discard_const(new_argv));
683 /* Should not happen */
687 talloc_free(new_argv);
689 ret = waitpid(pid, &status, 0);
692 fprintf(stderr, "waitpid() failed for %s - %s\n",
693 command, strerror(save_errno));
697 if (WIFEXITED(status)) {
698 int pstatus = WEXITSTATUS(status);
699 if (WIFSIGNALED(status)) {
700 fprintf(stderr, "%s terminated with signal %d\n",
701 command, WTERMSIG(status));
703 } else if (pstatus >= 64 && pstatus < 255) {
704 fprintf(stderr, "%s failed with error %d\n",
705 command, pstatus-64);
711 } else if (WIFSIGNALED(status)) {
712 fprintf(stderr, "%s terminated with signal %d\n",
713 command, WTERMSIG(status));
724 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
725 int argc, const char **argv)
727 printf("%s\n", CTDB_VERSION_STRING);
731 static bool partially_online(TALLOC_CTX *mem_ctx,
732 struct ctdb_context *ctdb,
733 struct ctdb_node_and_flags *node)
735 struct ctdb_iface_list *iface_list;
739 if (node->flags != 0) {
743 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
744 node->pnn, TIMEOUT(), &iface_list);
750 for (i=0; i < iface_list->num; i++) {
751 if (iface_list->iface[i].link_state == 0) {
760 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
761 struct ctdb_context *ctdb,
762 struct ctdb_node_map *nodemap,
765 struct ctdb_node_and_flags *node;
768 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
772 "Disconnected", options.sep,
773 "Banned", options.sep,
774 "Disabled", options.sep,
775 "Unhealthy", options.sep,
776 "Stopped", options.sep,
777 "Inactive", options.sep,
778 "PartiallyOnline", options.sep,
779 "ThisNode", options.sep);
781 for (i=0; i<nodemap->num; i++) {
782 node = &nodemap->node[i];
783 if (node->flags & NODE_FLAGS_DELETED) {
787 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
789 node->pnn, options.sep,
790 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
792 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
793 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
794 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
796 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
797 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
798 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
799 partially_online(mem_ctx, ctdb, node), options.sep,
800 (node->pnn == mypnn)?'Y':'N', options.sep);
805 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
806 struct ctdb_node_map *nodemap, uint32_t mypnn,
809 struct ctdb_node_and_flags *node;
810 int num_deleted_nodes = 0;
813 for (i=0; i<nodemap->num; i++) {
814 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
820 if (num_deleted_nodes == 0) {
821 printf("Number of nodes:%d\n", nodemap->num);
823 printf("Number of nodes:%d "
824 "(including %d deleted nodes)\n",
825 nodemap->num, num_deleted_nodes);
829 for (i=0; i<nodemap->num; i++) {
830 node = &nodemap->node[i];
831 if (node->flags & NODE_FLAGS_DELETED) {
835 printf("pnn:%u %-16s %s%s\n",
837 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
838 partially_online(mem_ctx, ctdb, node) ?
840 pretty_print_flags(mem_ctx, node->flags),
841 node->pnn == mypnn ? " (THIS NODE)" : "");
845 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
846 struct ctdb_node_map *nodemap, uint32_t mypnn,
847 struct ctdb_vnn_map *vnnmap, int recmode,
852 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
854 if (vnnmap->generation == INVALID_GENERATION) {
855 printf("Generation:INVALID\n");
857 printf("Generation:%u\n", vnnmap->generation);
859 printf("Size:%d\n", vnnmap->size);
860 for (i=0; i<vnnmap->size; i++) {
861 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
864 printf("Recovery mode:%s (%d)\n",
865 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
867 printf("Recovery master:%d\n", recmaster);
870 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
871 int argc, const char **argv)
873 struct ctdb_node_map *nodemap;
874 struct ctdb_vnn_map *vnnmap;
883 nodemap = get_nodemap(ctdb, false);
884 if (nodemap == NULL) {
888 if (options.machinereadable == 1) {
889 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
893 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
894 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
899 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
900 ctdb->cmd_pnn, TIMEOUT(), &recmode);
905 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
906 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
911 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
916 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
917 int argc, const char **argv)
919 struct ctdb_uptime *uptime;
920 int ret, tmp, days, hours, minutes, seconds;
922 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
923 ctdb->cmd_pnn, TIMEOUT(), &uptime);
928 printf("Current time of node %-4u : %s",
929 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
931 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
932 seconds = tmp % 60; tmp /= 60;
933 minutes = tmp % 60; tmp /= 60;
934 hours = tmp % 24; tmp /= 24;
937 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
938 days, hours, minutes, seconds,
939 ctime(&uptime->ctdbd_start_time.tv_sec));
941 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
942 seconds = tmp % 60; tmp /= 60;
943 minutes = tmp % 60; tmp /= 60;
944 hours = tmp % 24; tmp /= 24;
947 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
948 days, hours, minutes, seconds,
949 ctime(&uptime->last_recovery_finished.tv_sec));
951 printf("Duration of last recovery/failover: %lf seconds\n",
952 timeval_delta(&uptime->last_recovery_finished,
953 &uptime->last_recovery_started));
958 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
959 int argc, const char **argv)
962 int ret, num_clients;
964 tv = timeval_current();
965 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
966 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
971 printf("response from %u time=%.6f sec (%d clients)\n",
972 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
976 const char *runstate_to_string(enum ctdb_runstate runstate);
977 enum ctdb_runstate runstate_from_string(const char *runstate_str);
979 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
980 int argc, const char **argv)
982 enum ctdb_runstate runstate;
986 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
987 ctdb->cmd_pnn, TIMEOUT(), &runstate);
993 for (i=0; i<argc; i++) {
994 enum ctdb_runstate t;
997 t = ctdb_runstate_from_string(argv[i]);
998 if (t == CTDB_RUNSTATE_UNKNOWN) {
999 printf("Invalid run state (%s)\n", argv[i]);
1003 if (t == runstate) {
1010 printf("CTDB not in required run state (got %s)\n",
1011 ctdb_runstate_to_string(runstate));
1015 printf("%s\n", ctdb_runstate_to_string(runstate));
1019 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1020 int argc, const char **argv)
1022 struct ctdb_var_list *tun_var_list;
1031 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1032 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1035 "Failed to get list of variables from node %u\n",
1041 for (i=0; i<tun_var_list->count; i++) {
1042 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1049 printf("No such tunable %s\n", argv[0]);
1053 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1054 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1059 printf("%-26s = %u\n", argv[0], value);
1063 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1064 int argc, const char **argv)
1066 struct ctdb_var_list *tun_var_list;
1067 struct ctdb_tunable tunable;
1075 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1076 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1079 "Failed to get list of variables from node %u\n",
1085 for (i=0; i<tun_var_list->count; i++) {
1086 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1093 printf("No such tunable %s\n", argv[0]);
1097 tunable.name = argv[0];
1098 tunable.value = strtoul(argv[1], NULL, 0);
1100 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1101 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1105 "Setting obsolete tunable variable '%s'\n",
1114 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1115 int argc, const char **argv)
1117 struct ctdb_var_list *tun_var_list;
1124 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1125 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1130 for (i=0; i<tun_var_list->count; i++) {
1131 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1140 } stats_fields[] = {
1141 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1142 STATISTICS_FIELD(num_clients),
1143 STATISTICS_FIELD(frozen),
1144 STATISTICS_FIELD(recovering),
1145 STATISTICS_FIELD(num_recoveries),
1146 STATISTICS_FIELD(client_packets_sent),
1147 STATISTICS_FIELD(client_packets_recv),
1148 STATISTICS_FIELD(node_packets_sent),
1149 STATISTICS_FIELD(node_packets_recv),
1150 STATISTICS_FIELD(keepalive_packets_sent),
1151 STATISTICS_FIELD(keepalive_packets_recv),
1152 STATISTICS_FIELD(node.req_call),
1153 STATISTICS_FIELD(node.reply_call),
1154 STATISTICS_FIELD(node.req_dmaster),
1155 STATISTICS_FIELD(node.reply_dmaster),
1156 STATISTICS_FIELD(node.reply_error),
1157 STATISTICS_FIELD(node.req_message),
1158 STATISTICS_FIELD(node.req_control),
1159 STATISTICS_FIELD(node.reply_control),
1160 STATISTICS_FIELD(client.req_call),
1161 STATISTICS_FIELD(client.req_message),
1162 STATISTICS_FIELD(client.req_control),
1163 STATISTICS_FIELD(timeouts.call),
1164 STATISTICS_FIELD(timeouts.control),
1165 STATISTICS_FIELD(timeouts.traverse),
1166 STATISTICS_FIELD(locks.num_calls),
1167 STATISTICS_FIELD(locks.num_current),
1168 STATISTICS_FIELD(locks.num_pending),
1169 STATISTICS_FIELD(locks.num_failed),
1170 STATISTICS_FIELD(total_calls),
1171 STATISTICS_FIELD(pending_calls),
1172 STATISTICS_FIELD(childwrite_calls),
1173 STATISTICS_FIELD(pending_childwrite_calls),
1174 STATISTICS_FIELD(memory_used),
1175 STATISTICS_FIELD(max_hop_count),
1176 STATISTICS_FIELD(total_ro_delegations),
1177 STATISTICS_FIELD(total_ro_revokes),
1180 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1182 static void print_statistics_machine(struct ctdb_statistics *s,
1188 printf("CTDB version%s", options.sep);
1189 printf("Current time of statistics%s", options.sep);
1190 printf("Statistics collected since%s", options.sep);
1191 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1192 printf("%s%s", stats_fields[i].name, options.sep);
1194 printf("num_reclock_ctdbd_latency%s", options.sep);
1195 printf("min_reclock_ctdbd_latency%s", options.sep);
1196 printf("avg_reclock_ctdbd_latency%s", options.sep);
1197 printf("max_reclock_ctdbd_latency%s", options.sep);
1199 printf("num_reclock_recd_latency%s", options.sep);
1200 printf("min_reclock_recd_latency%s", options.sep);
1201 printf("avg_reclock_recd_latency%s", options.sep);
1202 printf("max_reclock_recd_latency%s", options.sep);
1204 printf("num_call_latency%s", options.sep);
1205 printf("min_call_latency%s", options.sep);
1206 printf("avg_call_latency%s", options.sep);
1207 printf("max_call_latency%s", options.sep);
1209 printf("num_lockwait_latency%s", options.sep);
1210 printf("min_lockwait_latency%s", options.sep);
1211 printf("avg_lockwait_latency%s", options.sep);
1212 printf("max_lockwait_latency%s", options.sep);
1214 printf("num_childwrite_latency%s", options.sep);
1215 printf("min_childwrite_latency%s", options.sep);
1216 printf("avg_childwrite_latency%s", options.sep);
1217 printf("max_childwrite_latency%s", options.sep);
1221 printf("%u%s", CTDB_PROTOCOL, options.sep);
1222 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1223 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1224 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1226 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1229 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1230 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1231 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1232 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1234 printf("%u%s", s->reclock.recd.num, options.sep);
1235 printf("%.6f%s", s->reclock.recd.min, options.sep);
1236 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1237 printf("%.6f%s", s->reclock.recd.max, options.sep);
1239 printf("%d%s", s->call_latency.num, options.sep);
1240 printf("%.6f%s", s->call_latency.min, options.sep);
1241 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1242 printf("%.6f%s", s->call_latency.max, options.sep);
1244 printf("%d%s", s->childwrite_latency.num, options.sep);
1245 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1246 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1247 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1251 static void print_statistics(struct ctdb_statistics *s)
1253 int tmp, days, hours, minutes, seconds;
1255 const char *prefix = NULL;
1258 tmp = s->statistics_current_time.tv_sec -
1259 s->statistics_start_time.tv_sec;
1260 seconds = tmp % 60; tmp /= 60;
1261 minutes = tmp % 60; tmp /= 60;
1262 hours = tmp % 24; tmp /= 24;
1265 printf("CTDB version %u\n", CTDB_PROTOCOL);
1266 printf("Current time of statistics : %s",
1267 ctime(&s->statistics_current_time.tv_sec));
1268 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1269 days, hours, minutes, seconds,
1270 ctime(&s->statistics_start_time.tv_sec));
1272 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1273 if (strchr(stats_fields[i].name, '.') != NULL) {
1274 preflen = strcspn(stats_fields[i].name, ".") + 1;
1276 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1277 prefix = stats_fields[i].name;
1278 printf(" %*.*s\n", preflen-1, preflen-1,
1279 stats_fields[i].name);
1284 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1285 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1286 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1289 printf(" hop_count_buckets:");
1290 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1291 printf(" %d", s->hop_count_bucket[i]);
1294 printf(" lock_buckets:");
1295 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1296 printf(" %d", s->locks.buckets[i]);
1299 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1300 "locks_latency MIN/AVG/MAX",
1301 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1302 s->locks.latency.max, s->locks.latency.num);
1304 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1305 "reclock_ctdbd MIN/AVG/MAX",
1306 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1307 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1309 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1310 "reclock_recd MIN/AVG/MAX",
1311 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1312 s->reclock.recd.max, s->reclock.recd.num);
1314 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1315 "call_latency MIN/AVG/MAX",
1316 s->call_latency.min, LATENCY_AVG(s->call_latency),
1317 s->call_latency.max, s->call_latency.num);
1319 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1320 "childwrite_latency MIN/AVG/MAX",
1321 s->childwrite_latency.min,
1322 LATENCY_AVG(s->childwrite_latency),
1323 s->childwrite_latency.max, s->childwrite_latency.num);
1326 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1327 int argc, const char **argv)
1329 struct ctdb_statistics *stats;
1333 usage("statistics");
1336 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1337 ctdb->cmd_pnn, TIMEOUT(), &stats);
1342 if (options.machinereadable) {
1343 print_statistics_machine(stats, true);
1345 print_statistics(stats);
1351 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1352 struct ctdb_context *ctdb,
1353 int argc, const char **argv)
1358 usage("statisticsreset");
1361 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1362 ctdb->cmd_pnn, TIMEOUT());
1370 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1371 int argc, const char **argv)
1373 struct ctdb_statistics_list *slist;
1374 int ret, count = 0, i;
1375 bool show_header = true;
1382 count = atoi(argv[0]);
1385 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1386 ctdb->cmd_pnn, TIMEOUT(), &slist);
1391 for (i=0; i<slist->num; i++) {
1392 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1395 if (options.machinereadable == 1) {
1396 print_statistics_machine(&slist->stats[i],
1398 show_header = false;
1400 print_statistics(&slist->stats[i]);
1402 if (count > 0 && i == count) {
1410 static int ctdb_public_ip_cmp(const void *a, const void *b)
1412 const struct ctdb_public_ip *ip_a = a;
1413 const struct ctdb_public_ip *ip_b = b;
1415 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1418 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1419 struct ctdb_public_ip_list *ips,
1420 struct ctdb_public_ip_info **ipinfo,
1424 char *conf, *avail, *active;
1426 if (options.machinereadable == 1) {
1427 printf("%s%s%s%s%s", options.sep,
1428 "Public IP", options.sep,
1429 "Node", options.sep);
1430 if (options.verbose == 1) {
1431 printf("%s%s%s%s%s%s\n",
1432 "ActiveInterfaces", options.sep,
1433 "AvailableInterfaces", options.sep,
1434 "ConfiguredInterfaces", options.sep);
1440 printf("Public IPs on ALL nodes\n");
1442 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1446 for (i = 0; i < ips->num; i++) {
1448 if (options.machinereadable == 1) {
1449 printf("%s%s%s%d%s", options.sep,
1450 ctdb_sock_addr_to_string(
1451 mem_ctx, &ips->ip[i].addr),
1453 (int)ips->ip[i].pnn, options.sep);
1455 printf("%s", ctdb_sock_addr_to_string(
1456 mem_ctx, &ips->ip[i].addr));
1459 if (options.verbose == 0) {
1460 if (options.machinereadable == 1) {
1463 printf(" %d\n", (int)ips->ip[i].pnn);
1472 if (ipinfo[i] == NULL) {
1476 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1477 struct ctdb_iface *iface;
1479 iface = &ipinfo[i]->ifaces->iface[j];
1481 conf = talloc_strdup(mem_ctx, iface->name);
1483 conf = talloc_asprintf_append(
1484 conf, ",%s", iface->name);
1487 if (ipinfo[i]->active_idx == j) {
1488 active = iface->name;
1491 if (iface->link_state == 0) {
1495 if (avail == NULL) {
1496 avail = talloc_strdup(mem_ctx, iface->name);
1498 avail = talloc_asprintf_append(
1499 avail, ",%s", iface->name);
1505 if (options.machinereadable == 1) {
1506 printf("%s%s%s%s%s%s\n",
1507 active ? active : "", options.sep,
1508 avail ? avail : "", options.sep,
1509 conf ? conf : "", options.sep);
1511 printf(" node[%d] active[%s] available[%s]"
1512 " configured[%s]\n",
1513 (int)ips->ip[i].pnn, active ? active : "",
1514 avail ? avail : "", conf ? conf : "");
1519 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1520 size_t datalen, void *private_data)
1522 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1523 private_data, struct ctdb_public_ip_list);
1524 struct ctdb_public_ip *ip;
1526 ip = (struct ctdb_public_ip *)databuf;
1527 ips->ip[ips->num] = *ip;
1533 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1534 struct ctdb_public_ip_list **out)
1536 struct ctdb_node_map *nodemap;
1537 struct ctdb_public_ip_list *ips;
1538 struct db_hash_context *ipdb;
1540 int ret, count, i, j;
1542 nodemap = get_nodemap(ctdb, false);
1543 if (nodemap == NULL) {
1547 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1552 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1558 for (i=0; i<count; i++) {
1559 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1560 pnn_list[i], TIMEOUT(),
1566 for (j=0; j<ips->num; j++) {
1567 struct ctdb_public_ip ip;
1569 ip.pnn = ips->ip[j].pnn;
1570 ip.addr = ips->ip[j].addr;
1572 if (pnn_list[i] == ip.pnn) {
1573 /* Node claims IP is hosted on it, so
1574 * save that information
1576 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1578 (uint8_t *)&ip, sizeof(ip));
1583 /* Node thinks IP is hosted elsewhere,
1584 * so overwrite with CTDB_UNKNOWN_PNN
1585 * if there's no existing entry
1587 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1589 if (ret == ENOENT) {
1590 ip.pnn = CTDB_UNKNOWN_PNN;
1591 ret = db_hash_add(ipdb,
1592 (uint8_t *)&ip.addr,
1606 talloc_free(pnn_list);
1608 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1613 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1618 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1619 if (ips->ip == NULL) {
1623 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1628 if (count != ips->num) {
1642 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1643 int argc, const char **argv)
1645 struct ctdb_public_ip_list *ips;
1646 struct ctdb_public_ip_info **ipinfo;
1648 bool do_all = false;
1655 if (strcmp(argv[0], "all") == 0) {
1663 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1665 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1666 ctdb->cmd_pnn, TIMEOUT(),
1673 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1674 ctdb_public_ip_cmp);
1676 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1677 if (ipinfo == NULL) {
1681 for (i=0; i<ips->num; i++) {
1684 pnn = ips->ip[i].pnn;
1686 pnn = ctdb->cmd_pnn;
1688 if (pnn == CTDB_UNKNOWN_PNN) {
1692 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1694 TIMEOUT(), &ips->ip[i].addr,
1701 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1705 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1706 int argc, const char **argv)
1708 struct ctdb_public_ip_info *ipinfo;
1709 ctdb_sock_addr addr;
1716 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1717 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1721 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1722 ctdb->cmd_pnn, TIMEOUT(), &addr,
1726 printf("Node %u does not know about IP %s\n",
1727 ctdb->cmd_pnn, argv[0]);
1732 printf("Public IP[%s] info on node %u\n",
1733 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1736 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1737 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1738 ipinfo->ip.pnn, ipinfo->ifaces->num);
1740 for (i=0; i<ipinfo->ifaces->num; i++) {
1741 struct ctdb_iface *iface;
1743 iface = &ipinfo->ifaces->iface[i];
1744 iface->name[CTDB_IFACE_SIZE] = '\0';
1745 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1747 iface->link_state == 0 ? "down" : "up",
1749 (i == ipinfo->active_idx) ? " (active)" : "");
1755 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1756 int argc, const char **argv)
1758 struct ctdb_iface_list *ifaces;
1765 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1766 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1771 if (ifaces->num == 0) {
1772 printf("No interfaces configured on node %u\n",
1777 if (options.machinereadable) {
1778 printf("%s%s%s%s%s%s%s\n", options.sep,
1779 "Name", options.sep,
1780 "LinkStatus", options.sep,
1781 "References", options.sep);
1783 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1786 for (i=0; i<ifaces->num; i++) {
1787 if (options.machinereadable) {
1788 printf("%s%s%s%u%s%u%s\n", options.sep,
1789 ifaces->iface[i].name, options.sep,
1790 ifaces->iface[i].link_state, options.sep,
1791 ifaces->iface[i].references, options.sep);
1793 printf("name:%s link:%s references:%u\n",
1794 ifaces->iface[i].name,
1795 ifaces->iface[i].link_state ? "up" : "down",
1796 ifaces->iface[i].references);
1803 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1804 int argc, const char **argv)
1806 struct ctdb_iface_list *ifaces;
1807 struct ctdb_iface *iface;
1811 usage("setifacelink");
1814 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1815 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1819 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1820 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1823 "Failed to get interface information from node %u\n",
1829 for (i=0; i<ifaces->num; i++) {
1830 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1831 iface = &ifaces->iface[i];
1836 if (iface == NULL) {
1837 printf("Interface %s not configured on node %u\n",
1838 argv[0], ctdb->cmd_pnn);
1842 if (strcmp(argv[1], "up") == 0) {
1843 iface->link_state = 1;
1844 } else if (strcmp(argv[1], "down") == 0) {
1845 iface->link_state = 0;
1847 usage("setifacelink");
1851 iface->references = 0;
1853 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1854 ctdb->cmd_pnn, TIMEOUT(), iface);
1862 static int control_process_exists(TALLOC_CTX *mem_ctx,
1863 struct ctdb_context *ctdb,
1864 int argc, const char **argv)
1870 usage("process-exists");
1873 pid = atoi(argv[0]);
1874 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1875 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1881 printf("PID %u exists\n", pid);
1883 printf("PID %u does not exist\n", pid);
1888 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1889 int argc, const char **argv)
1891 struct ctdb_dbid_map *dbmap;
1898 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1899 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1904 if (options.machinereadable == 1) {
1905 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1908 "Name", options.sep,
1909 "Path", options.sep,
1910 "Persistent", options.sep,
1911 "Sticky", options.sep,
1912 "Unhealthy", options.sep,
1913 "Readonly", options.sep,
1914 "Replicated", options.sep);
1916 printf("Number of databases:%d\n", dbmap->num);
1919 for (i=0; i<dbmap->num; i++) {
1929 db_id = dbmap->dbs[i].db_id;
1931 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1932 ctdb->cmd_pnn, TIMEOUT(), db_id,
1938 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1939 ctdb->cmd_pnn, TIMEOUT(), db_id,
1945 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1946 ctdb->cmd_pnn, TIMEOUT(), db_id,
1952 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1953 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1954 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1955 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
1957 if (options.machinereadable == 1) {
1958 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1963 !! (persistent), options.sep,
1964 !! (sticky), options.sep,
1965 !! (health), options.sep,
1966 !! (readonly), options.sep,
1967 !! (replicated), options.sep);
1969 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1971 persistent ? " PERSISTENT" : "",
1972 sticky ? " STICKY" : "",
1973 readonly ? " READONLY" : "",
1974 replicated ? " REPLICATED" : "",
1975 health ? " UNHEALTHY" : "");
1978 talloc_free(discard_const(name));
1979 talloc_free(discard_const(path));
1980 talloc_free(discard_const(health));
1986 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1987 int argc, const char **argv)
1990 const char *db_name, *db_path, *db_health;
1995 usage("getdbstatus");
1998 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2002 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2003 ctdb->cmd_pnn, TIMEOUT(), db_id,
2009 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2010 ctdb->cmd_pnn, TIMEOUT(), db_id,
2016 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2017 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2018 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2019 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2020 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2021 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2022 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2026 struct dump_record_state {
2030 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2032 static void dump_tdb_data(const char *name, TDB_DATA val)
2036 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2037 for (i=0; i<val.dsize; i++) {
2038 if (ISASCII(val.dptr[i])) {
2039 fprintf(stdout, "%c", val.dptr[i]);
2041 fprintf(stdout, "\\%02X", val.dptr[i]);
2044 fprintf(stdout, "\"\n");
2047 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2049 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2050 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2051 fprintf(stdout, "flags: 0x%08x", header->flags);
2052 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2053 fprintf(stdout, " MIGRATED_WITH_DATA");
2055 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2056 fprintf(stdout, " VACUUM_MIGRATED");
2058 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2059 fprintf(stdout, " AUTOMATIC");
2061 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2062 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2064 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2065 fprintf(stdout, " RO_HAVE_READONLY");
2067 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2068 fprintf(stdout, " RO_REVOKING_READONLY");
2070 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2071 fprintf(stdout, " RO_REVOKE_COMPLETE");
2073 fprintf(stdout, "\n");
2077 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2078 TDB_DATA key, TDB_DATA data, void *private_data)
2080 struct dump_record_state *state =
2081 (struct dump_record_state *)private_data;
2085 dump_tdb_data("key", key);
2086 dump_ltdb_header(header);
2087 dump_tdb_data("data", data);
2088 fprintf(stdout, "\n");
2093 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2094 int argc, const char **argv)
2096 struct ctdb_db_context *db;
2097 const char *db_name;
2100 struct dump_record_state state;
2107 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2111 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2114 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2120 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2121 ctdb->cmd_pnn, TIMEOUT(),
2122 dump_record, &state);
2124 printf("Dumped %u records\n", state.count);
2129 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2130 int argc, const char **argv)
2132 struct ctdb_db_context *db;
2133 const char *db_name;
2136 struct dump_record_state state;
2143 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2147 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2150 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2155 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2157 printf("Dumped %u record(s)\n", state.count);
2162 static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2163 int argc, const char **argv)
2168 usage("getmonmode");
2171 ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
2172 ctdb->cmd_pnn, TIMEOUT(), &mode);
2178 (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
2182 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2183 struct ctdb_context *ctdb,
2184 int argc, const char **argv)
2190 usage("getcapabilities");
2193 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2194 ctdb->cmd_pnn, TIMEOUT(), &caps);
2199 if (options.machinereadable == 1) {
2200 printf("%s%s%s%s%s\n",
2202 "RECMASTER", options.sep,
2203 "LMASTER", options.sep);
2204 printf("%s%d%s%d%s\n", options.sep,
2205 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2206 !! (caps & CTDB_CAP_LMASTER), options.sep);
2208 printf("RECMASTER: %s\n",
2209 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2210 printf("LMASTER: %s\n",
2211 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2217 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2218 int argc, const char **argv)
2220 printf("%u\n", ctdb_client_pnn(ctdb->client));
2224 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2225 int argc, const char **argv)
2227 char *t, *lvs_helper = NULL;
2233 t = getenv("CTDB_LVS_HELPER");
2235 lvs_helper = talloc_strdup(mem_ctx, t);
2237 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2238 CTDB_HELPER_BINDIR);
2241 if (lvs_helper == NULL) {
2242 fprintf(stderr, "Unable to set LVS helper\n");
2246 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2249 static int control_disable_monitor(TALLOC_CTX *mem_ctx,
2250 struct ctdb_context *ctdb,
2251 int argc, const char **argv)
2256 usage("disablemonitor");
2259 ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2260 ctdb->cmd_pnn, TIMEOUT());
2268 static int control_enable_monitor(TALLOC_CTX *mem_ctx,
2269 struct ctdb_context *ctdb,
2270 int argc, const char **argv)
2275 usage("enablemonitor");
2278 ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2279 ctdb->cmd_pnn, TIMEOUT());
2287 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2288 int argc, const char **argv)
2298 found = debug_level_parse(argv[0], &log_level);
2301 "Invalid debug level '%s'. Valid levels are:\n",
2303 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2307 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2308 ctdb->cmd_pnn, TIMEOUT(), log_level);
2316 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2317 int argc, const char **argv)
2320 const char *log_str;
2327 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2328 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2333 log_str = debug_level_to_string(loglevel);
2334 printf("%s\n", log_str);
2339 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2340 int argc, const char **argv)
2342 const char *db_name;
2343 uint8_t db_flags = 0;
2346 if (argc < 1 || argc > 2) {
2352 if (strcmp(argv[1], "persistent") == 0) {
2353 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2354 } else if (strcmp(argv[1], "readonly") == 0) {
2355 db_flags = CTDB_DB_FLAGS_READONLY;
2356 } else if (strcmp(argv[1], "sticky") == 0) {
2357 db_flags = CTDB_DB_FLAGS_STICKY;
2358 } else if (strcmp(argv[1], "replicated") == 0) {
2359 db_flags = CTDB_DB_FLAGS_REPLICATED;
2365 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2374 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2375 int argc, const char **argv)
2377 const char *db_name;
2380 struct ctdb_node_map *nodemap;
2388 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2389 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2394 if (recmode == CTDB_RECOVERY_ACTIVE) {
2395 fprintf(stderr, "Database cannot be detached"
2396 " when recovery is active\n");
2400 nodemap = get_nodemap(ctdb, false);
2401 if (nodemap == NULL) {
2405 for (i=0; i<nodemap->num; i++) {
2408 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2411 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2414 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2415 fprintf(stderr, "Database cannot be detached on"
2416 " inactive (stopped or banned) node %u\n",
2417 nodemap->node[i].pnn);
2421 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2422 nodemap->node[i].pnn, TIMEOUT(),
2423 "AllowClientDBAttach", &value);
2426 "Unable to get tunable AllowClientDBAttach"
2427 " from node %u\n", nodemap->node[i].pnn);
2433 "Database access is still active on node %u."
2434 " Set AllowclientDBAttach=0 on all nodes.\n",
2435 nodemap->node[i].pnn);
2441 for (i=0; i<argc; i++) {
2442 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2448 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2450 "Only volatile databases can be detached\n");
2454 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2456 fprintf(stderr, "Database %s detach failed\n", db_name);
2464 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2465 int argc, const char **argv)
2467 const char *mem_str;
2471 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2472 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2477 n = write(1, mem_str, strlen(mem_str)+1);
2478 if (n < 0 || n != strlen(mem_str)+1) {
2479 fprintf(stderr, "Failed to write talloc summary\n");
2486 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2488 bool *done = (bool *)private_data;
2491 n = write(1, data.dptr, data.dsize);
2492 if (n < 0 || n != data.dsize) {
2493 fprintf(stderr, "Failed to write talloc summary\n");
2499 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2500 int argc, const char **argv)
2502 struct ctdb_srvid_message msg = { 0 };
2506 msg.pnn = ctdb->pnn;
2507 msg.srvid = next_srvid(ctdb);
2509 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2510 msg.srvid, dump_memory, &done);
2515 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2516 ctdb->cmd_pnn, &msg);
2521 ctdb_client_wait(ctdb->ev, &done);
2525 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2526 int argc, const char **argv)
2531 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2532 ctdb->cmd_pnn, TIMEOUT(), &pid);
2537 printf("%u\n", pid);
2541 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2542 const char *desc, uint32_t flag, bool set_flag)
2544 struct ctdb_node_map *nodemap;
2547 nodemap = get_nodemap(ctdb, false);
2548 if (nodemap == NULL) {
2552 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2553 if (set_flag == flag_is_set) {
2555 fprintf(stderr, "Node %u is already %s\n",
2556 ctdb->cmd_pnn, desc);
2558 fprintf(stderr, "Node %u is not %s\n",
2559 ctdb->cmd_pnn, desc);
2567 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2568 uint32_t flag, bool set_flag)
2570 struct ctdb_node_map *nodemap;
2574 nodemap = get_nodemap(ctdb, true);
2575 if (nodemap == NULL) {
2577 "Failed to get nodemap, trying again\n");
2582 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2583 if (flag_is_set == set_flag) {
2591 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2592 struct ctdb_client_context *client,
2593 uint32_t destnode, struct timeval timeout,
2594 uint32_t set, uint32_t clear)
2596 struct ctdb_node_map *nodemap;
2597 struct ctdb_node_flag_change flag_change;
2598 struct ctdb_req_control request;
2602 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2603 tevent_timeval_zero(), &nodemap);
2608 flag_change.pnn = destnode;
2609 flag_change.old_flags = nodemap->node[destnode].flags;
2610 flag_change.new_flags = flag_change.old_flags | set;
2611 flag_change.new_flags &= ~clear;
2613 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2618 ctdb_req_control_modify_flags(&request, &flag_change);
2619 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2620 tevent_timeval_zero(), &request,
2625 struct ipreallocate_state {
2630 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2633 struct ipreallocate_state *state =
2634 (struct ipreallocate_state *)private_data;
2636 if (data.dsize != sizeof(int)) {
2641 state->status = *(int *)data.dptr;
2645 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2647 struct ctdb_srvid_message msg = { 0 };
2648 struct ipreallocate_state state;
2651 msg.pnn = ctdb->pnn;
2652 msg.srvid = next_srvid(ctdb);
2655 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2657 ipreallocate_handler, &state);
2663 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2665 CTDB_BROADCAST_CONNECTED,
2671 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2677 if (state.status >= 0) {
2686 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2691 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2692 int argc, const char **argv)
2700 ret = check_flags(mem_ctx, ctdb, "disabled",
2701 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2706 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2707 ctdb->cmd_pnn, TIMEOUT(),
2708 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2711 "Failed to set DISABLED flag on node %u\n",
2716 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2717 return ipreallocate(mem_ctx, ctdb);
2720 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2721 int argc, const char **argv)
2729 ret = check_flags(mem_ctx, ctdb, "disabled",
2730 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2735 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2736 ctdb->cmd_pnn, TIMEOUT(),
2737 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2739 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2744 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2745 return ipreallocate(mem_ctx, ctdb);
2748 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2749 int argc, const char **argv)
2757 ret = check_flags(mem_ctx, ctdb, "stopped",
2758 NODE_FLAGS_STOPPED, true);
2763 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2764 ctdb->cmd_pnn, TIMEOUT());
2766 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2770 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2771 return ipreallocate(mem_ctx, ctdb);
2774 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2775 int argc, const char **argv)
2783 ret = check_flags(mem_ctx, ctdb, "stopped",
2784 NODE_FLAGS_STOPPED, false);
2789 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2790 ctdb->cmd_pnn, TIMEOUT());
2792 fprintf(stderr, "Failed to continue stopped node %u\n",
2797 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2798 return ipreallocate(mem_ctx, ctdb);
2801 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2802 int argc, const char **argv)
2804 struct ctdb_ban_state ban_state;
2811 ret = check_flags(mem_ctx, ctdb, "banned",
2812 NODE_FLAGS_BANNED, true);
2817 ban_state.pnn = ctdb->cmd_pnn;
2818 ban_state.time = strtoul(argv[0], NULL, 0);
2820 if (ban_state.time == 0) {
2821 fprintf(stderr, "Ban time cannot be zero\n");
2825 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2826 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2828 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2832 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2833 return ipreallocate(mem_ctx, ctdb);
2837 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2838 int argc, const char **argv)
2840 struct ctdb_ban_state ban_state;
2847 ret = check_flags(mem_ctx, ctdb, "banned",
2848 NODE_FLAGS_BANNED, false);
2853 ban_state.pnn = ctdb->cmd_pnn;
2856 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2857 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2859 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2863 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2864 return ipreallocate(mem_ctx, ctdb);
2868 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2869 int argc, const char **argv)
2877 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2878 ctdb->cmd_pnn, TIMEOUT());
2880 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2887 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2888 uint32_t *generation)
2892 struct ctdb_vnn_map *vnnmap;
2896 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2897 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2899 fprintf(stderr, "Failed to find recovery master\n");
2903 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2904 recmaster, TIMEOUT(), &recmode);
2906 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2911 if (recmode == CTDB_RECOVERY_ACTIVE) {
2916 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2917 recmaster, TIMEOUT(), &vnnmap);
2919 fprintf(stderr, "Failed to get generation from node %u\n",
2924 if (vnnmap->generation == INVALID_GENERATION) {
2925 talloc_free(vnnmap);
2930 *generation = vnnmap->generation;
2931 talloc_free(vnnmap);
2936 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2937 int argc, const char **argv)
2939 uint32_t generation, next_generation;
2946 ret = get_generation(mem_ctx, ctdb, &generation);
2951 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2952 ctdb->cmd_pnn, TIMEOUT(),
2953 CTDB_RECOVERY_ACTIVE);
2955 fprintf(stderr, "Failed to set recovery mode active\n");
2960 ret = get_generation(mem_ctx, ctdb, &next_generation);
2963 "Failed to confirm end of recovery\n");
2967 if (next_generation != generation) {
2977 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2978 int argc, const char **argv)
2981 usage("ipreallocate");
2984 return ipreallocate(mem_ctx, ctdb);
2987 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2988 struct ctdb_context *ctdb,
2989 int argc, const char **argv)
2995 usage("isnotrecmaster");
2998 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2999 ctdb->pnn, TIMEOUT(), &recmaster);
3001 fprintf(stderr, "Failed to get recmaster\n");
3005 if (recmaster != ctdb->pnn) {
3006 printf("this node is not the recmaster\n");
3010 printf("this node is the recmaster\n");
3014 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3015 int argc, const char **argv)
3017 struct ctdb_addr_info addr_info;
3024 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
3025 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3028 addr_info.iface = argv[1];
3030 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3031 ctdb->cmd_pnn, TIMEOUT(),
3034 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3042 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3043 int argc, const char **argv)
3045 ctdb_sock_addr src, dst;
3048 if (argc != 0 && argc != 2) {
3053 struct ctdb_connection *clist;
3057 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3063 for (i=0; i<count; i++) {
3064 ret = ctdb_sys_send_tcp(&clist[i].src,
3074 if (num_failed > 0) {
3075 fprintf(stderr, "Failed to send %d tickles\n",
3084 if (! parse_ip_port(argv[0], &src)) {
3085 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3089 if (! parse_ip_port(argv[1], &dst)) {
3090 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3094 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3096 fprintf(stderr, "Failed to send tickle ack\n");
3103 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3104 int argc, const char **argv)
3106 ctdb_sock_addr addr;
3107 struct ctdb_tickle_list *tickles;
3111 if (argc < 1 || argc > 2) {
3112 usage("gettickles");
3116 port = strtoul(argv[1], NULL, 10);
3119 if (! parse_ip(argv[0], NULL, port, &addr)) {
3120 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3124 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3125 ctdb->cmd_pnn, TIMEOUT(), &addr,
3128 fprintf(stderr, "Failed to get list of connections\n");
3132 if (options.machinereadable) {
3133 printf("%s%s%s%s%s%s%s%s%s\n",
3135 "Source IP", options.sep,
3136 "Port", options.sep,
3137 "Destiation IP", options.sep,
3138 "Port", options.sep);
3139 for (i=0; i<tickles->num; i++) {
3140 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3141 ctdb_sock_addr_to_string(
3142 mem_ctx, &tickles->conn[i].src),
3144 ntohs(tickles->conn[i].src.ip.sin_port),
3146 ctdb_sock_addr_to_string(
3147 mem_ctx, &tickles->conn[i].dst),
3149 ntohs(tickles->conn[i].dst.ip.sin_port),
3153 printf("Connections for IP: %s\n",
3154 ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
3155 printf("Num connections: %u\n", tickles->num);
3156 for (i=0; i<tickles->num; i++) {
3157 printf("SRC: %s:%u DST: %s:%u\n",
3158 ctdb_sock_addr_to_string(
3159 mem_ctx, &tickles->conn[i].src),
3160 ntohs(tickles->conn[i].src.ip.sin_port),
3161 ctdb_sock_addr_to_string(
3162 mem_ctx, &tickles->conn[i].dst),
3163 ntohs(tickles->conn[i].dst.ip.sin_port));
3167 talloc_free(tickles);
3171 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3172 struct ctdb_connection *conn);
3174 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3176 struct process_clist_state {
3177 struct ctdb_connection *clist;
3179 int num_failed, num_total;
3180 clist_reply_func reply_func;
3183 static void process_clist_done(struct tevent_req *subreq);
3185 static struct tevent_req *process_clist_send(
3186 TALLOC_CTX *mem_ctx,
3187 struct ctdb_context *ctdb,
3188 struct ctdb_connection *clist,
3190 clist_request_func request_func,
3191 clist_reply_func reply_func)
3193 struct tevent_req *req, *subreq;
3194 struct process_clist_state *state;
3195 struct ctdb_req_control request;
3198 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3203 state->clist = clist;
3204 state->count = count;
3205 state->reply_func = reply_func;
3207 for (i=0; i<count; i++) {
3208 request_func(&request, &clist[i]);
3209 subreq = ctdb_client_control_send(state, ctdb->ev,
3210 ctdb->client, ctdb->cmd_pnn,
3211 TIMEOUT(), &request);
3212 if (tevent_req_nomem(subreq, req)) {
3213 return tevent_req_post(req, ctdb->ev);
3215 tevent_req_set_callback(subreq, process_clist_done, req);
3221 static void process_clist_done(struct tevent_req *subreq)
3223 struct tevent_req *req = tevent_req_callback_data(
3224 subreq, struct tevent_req);
3225 struct process_clist_state *state = tevent_req_data(
3226 req, struct process_clist_state);
3227 struct ctdb_reply_control *reply;
3231 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3232 TALLOC_FREE(subreq);
3234 state->num_failed += 1;
3238 ret = state->reply_func(reply);
3240 state->num_failed += 1;
3245 state->num_total += 1;
3246 if (state->num_total == state->count) {
3247 tevent_req_done(req);
3251 static int process_clist_recv(struct tevent_req *req)
3253 struct process_clist_state *state = tevent_req_data(
3254 req, struct process_clist_state);
3256 return state->num_failed;
3259 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3260 int argc, const char **argv)
3262 struct ctdb_connection conn;
3265 if (argc != 0 && argc != 2) {
3270 struct ctdb_connection *clist;
3271 struct tevent_req *req;
3274 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3282 req = process_clist_send(mem_ctx, ctdb, clist, count,
3283 ctdb_req_control_tcp_add_delayed_update,
3284 ctdb_reply_control_tcp_add_delayed_update);
3290 tevent_req_poll(req, ctdb->ev);
3293 ret = process_clist_recv(req);
3295 fprintf(stderr, "Failed to add %d tickles\n", ret);
3302 if (! parse_ip_port(argv[0], &conn.src)) {
3303 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3306 if (! parse_ip_port(argv[1], &conn.dst)) {
3307 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3311 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3312 ctdb->client, ctdb->cmd_pnn,
3315 fprintf(stderr, "Failed to register connection\n");
3322 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3323 int argc, const char **argv)
3325 struct ctdb_connection conn;
3328 if (argc != 0 && argc != 2) {
3333 struct ctdb_connection *clist;
3334 struct tevent_req *req;
3337 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3345 req = process_clist_send(mem_ctx, ctdb, clist, count,
3346 ctdb_req_control_tcp_remove,
3347 ctdb_reply_control_tcp_remove);
3353 tevent_req_poll(req, ctdb->ev);
3356 ret = process_clist_recv(req);
3358 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3365 if (! parse_ip_port(argv[0], &conn.src)) {
3366 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3369 if (! parse_ip_port(argv[1], &conn.dst)) {
3370 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3374 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3375 ctdb->cmd_pnn, TIMEOUT(), &conn);
3377 fprintf(stderr, "Failed to unregister connection\n");
3384 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3385 int argc, const char **argv)
3387 struct ctdb_node_map *nodemap;
3394 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3395 if (nodemap == NULL) {
3399 for (i=0; i<nodemap->num; i++) {
3400 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3404 if (options.machinereadable) {
3405 printf("%s%u%s%s%s\n", options.sep,
3406 nodemap->node[i].pnn, options.sep,
3407 ctdb_sock_addr_to_string(
3408 mem_ctx, &nodemap->node[i].addr),
3412 ctdb_sock_addr_to_string(
3413 mem_ctx, &nodemap->node[i].addr));
3420 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3421 struct ctdb_node_map *nodemap2)
3425 if (nodemap1->num != nodemap2->num) {
3429 for (i=0; i<nodemap1->num; i++) {
3430 struct ctdb_node_and_flags *n1, *n2;
3432 n1 = &nodemap1->node[i];
3433 n2 = &nodemap2->node[i];
3435 if ((n1->pnn != n2->pnn) ||
3436 (n1->flags != n2->flags) ||
3437 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3445 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3446 struct ctdb_node_map *nm,
3447 struct ctdb_node_map *fnm,
3451 bool check_failed = false;
3455 for (i=0; i<nm->num; i++) {
3456 if (i >= fnm->num) {
3458 "Node %u (%s) missing from nodes file\n",
3460 ctdb_sock_addr_to_string(
3461 mem_ctx, &nm->node[i].addr));
3462 check_failed = true;
3465 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3466 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3467 /* Node remains deleted */
3471 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3472 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3473 /* Node not newly nor previously deleted */
3474 if (! ctdb_same_ip(&nm->node[i].addr,
3475 &fnm->node[i].addr)) {
3477 "Node %u has changed IP address"
3478 " (was %s, now %s)\n",
3480 ctdb_sock_addr_to_string(
3481 mem_ctx, &nm->node[i].addr),
3482 ctdb_sock_addr_to_string(
3483 mem_ctx, &fnm->node[i].addr));
3484 check_failed = true;
3486 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3488 "WARNING: Node %u is disconnected."
3489 " You MUST fix this node manually!\n",
3496 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3497 /* Node is being deleted */
3498 printf("Node %u is DELETED\n", nm->node[i].pnn);
3500 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3502 "ERROR: Node %u is still connected\n",
3504 check_failed = true;
3509 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3510 /* Node was previously deleted */
3511 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3518 "ERROR: Nodes will not be reloaded due to previous error\n");
3522 /* Leftover nodes in file are NEW */
3523 for (; i < fnm->num; i++) {
3524 printf("Node %u is NEW\n", fnm->node[i].pnn);
3531 struct disable_recoveries_state {
3539 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3542 struct disable_recoveries_state *state =
3543 (struct disable_recoveries_state *)private_data;
3546 if (data.dsize != sizeof(int)) {
3551 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3552 ret = *(int *)data.dptr;
3554 state->status = ret;
3558 for (i=0; i<state->node_count; i++) {
3559 if (state->pnn_list[i] == ret) {
3560 state->reply[i] = true;
3566 for (i=0; i<state->node_count; i++) {
3567 if (! state->reply[i]) {
3568 state->done = false;
3574 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3575 uint32_t timeout, uint32_t *pnn_list, int count)
3577 struct ctdb_disable_message disable = { 0 };
3578 struct disable_recoveries_state state;
3581 disable.pnn = ctdb->pnn;
3582 disable.srvid = next_srvid(ctdb);
3583 disable.timeout = timeout;
3585 state.pnn_list = pnn_list;
3586 state.node_count = count;
3589 state.reply = talloc_zero_array(mem_ctx, bool, count);
3590 if (state.reply == NULL) {
3594 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3596 disable_recoveries_handler,
3602 for (i=0; i<count; i++) {
3603 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3612 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3614 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3616 ret = (state.status >= 0 ? 0 : 1);
3620 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3621 disable.srvid, &state);
3625 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3626 int argc, const char **argv)
3628 struct ctdb_node_map *nodemap = NULL;
3629 struct ctdb_node_map *file_nodemap;
3630 struct ctdb_node_map *remote_nodemap;
3631 struct ctdb_req_control request;
3632 struct ctdb_reply_control **reply;
3638 nodemap = get_nodemap(ctdb, false);
3639 if (nodemap == NULL) {
3643 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3644 if (file_nodemap == NULL) {
3648 for (i=0; i<nodemap->num; i++) {
3649 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3653 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3654 nodemap->node[i].pnn, TIMEOUT(),
3658 "ERROR: Failed to get nodes file from node %u\n",
3659 nodemap->node[i].pnn);
3663 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3665 "ERROR: Nodes file on node %u differs"
3666 " from current node (%u)\n",
3667 nodemap->node[i].pnn, ctdb->pnn);
3672 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3678 fprintf(stderr, "No change in nodes file,"
3679 " skipping unnecessary reload\n");
3683 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3684 mem_ctx, &pnn_list);
3686 fprintf(stderr, "Memory allocation error\n");
3690 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3693 fprintf(stderr, "Failed to disable recoveries\n");
3697 ctdb_req_control_reload_nodes_file(&request);
3698 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3699 pnn_list, count, TIMEOUT(),
3700 &request, NULL, &reply);
3702 bool failed = false;
3704 for (i=0; i<count; i++) {
3705 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3708 "Node %u failed to reload nodes\n",
3715 "You MUST fix failed nodes manually!\n");
3719 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3721 fprintf(stderr, "Failed to enable recoveries\n");
3728 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3729 ctdb_sock_addr *addr, uint32_t pnn)
3731 struct ctdb_public_ip_list *pubip_list;
3732 struct ctdb_public_ip pubip;
3733 struct ctdb_node_map *nodemap;
3734 struct ctdb_req_control request;
3738 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3739 CTDB_BROADCAST_CONNECTED,
3740 2*options.timelimit);
3742 fprintf(stderr, "Failed to disable IP check\n");
3746 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3747 pnn, TIMEOUT(), false, &pubip_list);
3749 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3754 for (i=0; i<pubip_list->num; i++) {
3755 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3760 if (i == pubip_list->num) {
3761 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3762 pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
3766 nodemap = get_nodemap(ctdb, false);
3767 if (nodemap == NULL) {
3771 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3773 fprintf(stderr, "Memory allocation error\n");
3779 ctdb_req_control_release_ip(&request, &pubip);
3781 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3782 pnn_list, count, TIMEOUT(),
3783 &request, NULL, NULL);
3785 fprintf(stderr, "Failed to release IP on nodes\n");
3789 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3790 pnn, TIMEOUT(), &pubip);
3792 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3799 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3800 int argc, const char **argv)
3802 ctdb_sock_addr addr;
3804 int ret, retries = 0;
3810 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3811 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3815 pnn = strtoul(argv[1], NULL, 10);
3816 if (pnn == CTDB_UNKNOWN_PNN) {
3817 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3821 while (retries < 5) {
3822 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3832 fprintf(stderr, "Failed to move IP %s to node %u\n",
3840 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3845 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3846 CTDB_BROADCAST_CONNECTED, pnn);
3849 "Failed to ask recovery master to distribute IPs\n");
3856 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3857 int argc, const char **argv)
3859 ctdb_sock_addr addr;
3860 struct ctdb_public_ip_list *pubip_list;
3861 struct ctdb_addr_info addr_info;
3863 int ret, i, retries = 0;
3869 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3870 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3874 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3875 ctdb->cmd_pnn, TIMEOUT(),
3876 false, &pubip_list);
3878 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3883 for (i=0; i<pubip_list->num; i++) {
3884 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3885 fprintf(stderr, "Node already knows about IP %s\n",
3886 ctdb_sock_addr_to_string(mem_ctx, &addr));
3891 addr_info.addr = addr;
3892 addr_info.mask = mask;
3893 addr_info.iface = argv[1];
3895 while (retries < 5) {
3896 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3897 ctdb->cmd_pnn, TIMEOUT(),
3908 fprintf(stderr, "Failed to add public IP to node %u."
3909 " Giving up\n", ctdb->cmd_pnn);
3913 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3921 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3922 int argc, const char **argv)
3924 ctdb_sock_addr addr;
3925 struct ctdb_public_ip_list *pubip_list;
3926 struct ctdb_addr_info addr_info;
3933 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3934 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3938 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3939 ctdb->cmd_pnn, TIMEOUT(),
3940 false, &pubip_list);
3942 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3947 for (i=0; i<pubip_list->num; i++) {
3948 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3953 if (i == pubip_list->num) {
3954 fprintf(stderr, "Node does not know about IP address %s\n",
3955 ctdb_sock_addr_to_string(mem_ctx, &addr));
3959 addr_info.addr = addr;
3961 addr_info.iface = NULL;
3963 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3964 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3966 fprintf(stderr, "Failed to delete public IP from node %u\n",
3974 #define DB_VERSION 3
3975 #define MAX_DB_NAME 64
3976 #define MAX_REC_BUFFER_SIZE (100*1000)
3979 unsigned long version;
3981 unsigned long flags;
3984 char name[MAX_DB_NAME];
3987 struct backup_state {
3988 TALLOC_CTX *mem_ctx;
3989 struct ctdb_rec_buffer *recbuf;
3992 unsigned int nbuf, nrec;
3995 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
3996 TDB_DATA key, TDB_DATA data, void *private_data)
3998 struct backup_state *state = (struct backup_state *)private_data;
4002 if (state->recbuf == NULL) {
4003 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4005 if (state->recbuf == NULL) {
4010 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4016 len = ctdb_rec_buffer_len(state->recbuf);
4017 if (len < MAX_REC_BUFFER_SIZE) {
4021 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4023 fprintf(stderr, "Failed to write records to backup file\n");
4028 state->nrec += state->recbuf->count;
4029 TALLOC_FREE(state->recbuf);
4034 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4035 int argc, const char **argv)
4037 const char *db_name;
4038 struct ctdb_db_context *db;
4041 struct backup_state state;
4042 struct db_header db_hdr;
4049 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4053 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4056 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4060 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4063 fprintf(stderr, "Failed to open file %s for writing\n",
4068 /* Write empty header first */
4069 ZERO_STRUCT(db_hdr);
4070 ret = write(fd, &db_hdr, sizeof(struct db_header));
4074 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4078 state.mem_ctx = mem_ctx;
4079 state.recbuf = NULL;
4084 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4086 fprintf(stderr, "Failed to collect records from DB %s\n",
4092 if (state.recbuf != NULL) {
4093 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4096 "Failed to write records to backup file\n");
4102 state.nrec += state.recbuf->count;
4103 TALLOC_FREE(state.recbuf);
4106 db_hdr.version = DB_VERSION;
4107 db_hdr.timestamp = time(NULL);
4108 db_hdr.flags = db_flags;
4109 db_hdr.nbuf = state.nbuf;
4110 db_hdr.nrec = state.nrec;
4111 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4113 lseek(fd, 0, SEEK_SET);
4114 ret = write(fd, &db_hdr, sizeof(struct db_header));
4118 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4123 printf("Database backed up to %s\n", argv[1]);
4127 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4128 int argc, const char **argv)
4130 const char *db_name = NULL;
4131 struct ctdb_db_context *db;
4132 struct db_header db_hdr;
4133 struct ctdb_node_map *nodemap;
4134 struct ctdb_req_control request;
4135 struct ctdb_reply_control **reply;
4136 struct ctdb_transdb wipedb;
4137 struct ctdb_pulldb_ext pulldb;
4138 struct ctdb_rec_buffer *recbuf;
4139 uint32_t generation;
4145 if (argc < 1 || argc > 2) {
4149 fd = open(argv[0], O_RDONLY, 0600);
4152 fprintf(stderr, "Failed to open file %s for reading\n",
4161 ret = read(fd, &db_hdr, sizeof(struct db_header));
4165 fprintf(stderr, "Failed to read db header from file %s\n",
4169 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4171 if (db_hdr.version != DB_VERSION) {
4173 "Wrong version of backup file, expected %u, got %lu\n",
4174 DB_VERSION, db_hdr.version);
4179 if (db_name == NULL) {
4180 db_name = db_hdr.name;
4183 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4184 localtime(&db_hdr.timestamp));
4185 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4187 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4190 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4195 nodemap = get_nodemap(ctdb, false);
4196 if (nodemap == NULL) {
4197 fprintf(stderr, "Failed to get nodemap\n");
4202 ret = get_generation(mem_ctx, ctdb, &generation);
4204 fprintf(stderr, "Failed to get current generation\n");
4209 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4216 wipedb.db_id = ctdb_db_id(db);
4217 wipedb.tid = generation;
4219 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4220 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4221 ctdb->client, pnn_list, count,
4222 TIMEOUT(), &request, NULL, NULL);
4228 ctdb_req_control_db_transaction_start(&request, &wipedb);
4229 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4230 pnn_list, count, TIMEOUT(),
4231 &request, NULL, NULL);
4236 ctdb_req_control_wipe_database(&request, &wipedb);
4237 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4238 pnn_list, count, TIMEOUT(),
4239 &request, NULL, NULL);
4244 pulldb.db_id = ctdb_db_id(db);
4246 pulldb.srvid = SRVID_CTDB_PUSHDB;
4248 ctdb_req_control_db_push_start(&request, &pulldb);
4249 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4250 pnn_list, count, TIMEOUT(),
4251 &request, NULL, NULL);
4256 for (i=0; i<db_hdr.nbuf; i++) {
4257 struct ctdb_req_message message;
4261 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4266 data.dsize = ctdb_rec_buffer_len(recbuf);
4267 data.dptr = talloc_size(mem_ctx, data.dsize);
4268 if (data.dptr == NULL) {
4272 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4274 message.srvid = pulldb.srvid;
4275 message.data.data = data;
4277 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4285 talloc_free(recbuf);
4286 talloc_free(data.dptr);
4289 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4290 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4291 pnn_list, count, TIMEOUT(),
4292 &request, NULL, &reply);
4297 for (i=0; i<count; i++) {
4298 uint32_t num_records;
4300 ret = ctdb_reply_control_db_push_confirm(reply[i],
4303 fprintf(stderr, "Invalid response from node %u\n",
4308 if (num_records != db_hdr.nrec) {
4309 fprintf(stderr, "Node %u received %u of %lu records\n",
4310 pnn_list[i], num_records, db_hdr.nrec);
4315 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4316 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4317 pnn_list, count, TIMEOUT(),
4318 &request, NULL, NULL);
4323 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4324 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4325 pnn_list, count, TIMEOUT(),
4326 &request, NULL, NULL);
4331 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4332 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4333 ctdb->client, pnn_list, count,
4334 TIMEOUT(), &request, NULL, NULL);
4339 printf("Database %s restored\n", db_name);
4346 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4347 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4351 struct dumpdbbackup_state {
4352 ctdb_rec_parser_func_t parser;
4353 struct dump_record_state sub_state;
4356 static int dumpdbbackup_handler(uint32_t reqid,
4357 struct ctdb_ltdb_header *header,
4358 TDB_DATA key, TDB_DATA data,
4361 struct dumpdbbackup_state *state =
4362 (struct dumpdbbackup_state *)private_data;
4363 struct ctdb_ltdb_header hdr;
4366 ret = ctdb_ltdb_header_extract(&data, &hdr);
4371 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4374 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4375 int argc, const char **argv)
4377 struct db_header db_hdr;
4379 struct dumpdbbackup_state state;
4383 usage("dumpbackup");
4386 fd = open(argv[0], O_RDONLY, 0600);
4389 fprintf(stderr, "Failed to open file %s for reading\n",
4394 ret = read(fd, &db_hdr, sizeof(struct db_header));
4398 fprintf(stderr, "Failed to read db header from file %s\n",
4402 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4404 if (db_hdr.version != DB_VERSION) {
4406 "Wrong version of backup file, expected %u, got %lu\n",
4407 DB_VERSION, db_hdr.version);
4412 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4413 localtime(&db_hdr.timestamp));
4414 printf("Dumping database %s from backup @ %s\n",
4415 db_hdr.name, timebuf);
4417 state.parser = dump_record;
4418 state.sub_state.count = 0;
4420 for (i=0; i<db_hdr.nbuf; i++) {
4421 struct ctdb_rec_buffer *recbuf;
4423 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4425 fprintf(stderr, "Failed to read records\n");
4430 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4433 fprintf(stderr, "Failed to dump records\n");
4440 printf("Dumped %u record(s)\n", state.sub_state.count);
4444 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4445 int argc, const char **argv)
4447 const char *db_name;
4448 struct ctdb_db_context *db;
4451 struct ctdb_node_map *nodemap;
4452 struct ctdb_req_control request;
4453 struct ctdb_transdb wipedb;
4454 uint32_t generation;
4462 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4466 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4469 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4473 nodemap = get_nodemap(ctdb, false);
4474 if (nodemap == NULL) {
4475 fprintf(stderr, "Failed to get nodemap\n");
4479 ret = get_generation(mem_ctx, ctdb, &generation);
4481 fprintf(stderr, "Failed to get current generation\n");
4485 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4491 ctdb_req_control_db_freeze(&request, db_id);
4492 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4493 ctdb->client, pnn_list, count,
4494 TIMEOUT(), &request, NULL, NULL);
4499 wipedb.db_id = db_id;
4500 wipedb.tid = generation;
4502 ctdb_req_control_db_transaction_start(&request, &wipedb);
4503 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4504 pnn_list, count, TIMEOUT(),
4505 &request, NULL, NULL);
4510 ctdb_req_control_wipe_database(&request, &wipedb);
4511 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4512 pnn_list, count, TIMEOUT(),
4513 &request, NULL, NULL);
4518 ctdb_req_control_db_set_healthy(&request, db_id);
4519 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4520 pnn_list, count, TIMEOUT(),
4521 &request, NULL, NULL);
4526 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4527 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4528 pnn_list, count, TIMEOUT(),
4529 &request, NULL, NULL);
4534 ctdb_req_control_db_thaw(&request, db_id);
4535 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4536 ctdb->client, pnn_list, count,
4537 TIMEOUT(), &request, NULL, NULL);
4542 printf("Database %s wiped\n", db_name);
4547 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4548 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4552 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4553 int argc, const char **argv)
4558 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4559 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4564 printf("%u\n", recmaster);
4568 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4569 int argc, const char **argv)
4571 char *t, *event_helper = NULL;
4572 char *eventd_socket = NULL;
4573 const char **new_argv;
4576 t = getenv("CTDB_EVENT_HELPER");
4578 event_helper = talloc_strdup(mem_ctx, t);
4580 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb_event",
4581 CTDB_HELPER_BINDIR);
4584 if (event_helper == NULL) {
4585 fprintf(stderr, "Unable to set event daemon helper\n");
4589 t = getenv("CTDB_SOCKET");
4591 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4594 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4598 if (eventd_socket == NULL) {
4599 fprintf(stderr, "Unable to set event daemon socket\n");
4603 new_argv = talloc_array(mem_ctx, const char *, argc + 1);
4604 if (new_argv == NULL) {
4605 fprintf(stderr, "Memory allocation error\n");
4609 new_argv[0] = eventd_socket;
4610 for (i=0; i<argc; i++) {
4611 new_argv[i+1] = argv[i];
4614 return run_helper(mem_ctx, "event daemon helper", event_helper,
4618 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4619 int argc, const char **argv)
4621 const char *new_argv[3];
4624 usage("scriptstatus");
4627 new_argv[0] = "status";
4628 new_argv[1] = (argc == 0) ? "monitor" : argv[0];
4631 (void) control_event(mem_ctx, ctdb, 2, new_argv);
4635 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4636 int argc, const char **argv)
4638 char *t, *natgw_helper = NULL;
4644 t = getenv("CTDB_NATGW_HELPER");
4646 natgw_helper = talloc_strdup(mem_ctx, t);
4648 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4649 CTDB_HELPER_BINDIR);
4652 if (natgw_helper == NULL) {
4653 fprintf(stderr, "Unable to set NAT gateway helper\n");
4657 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4662 * Find the PNN of the current node
4663 * discover the pnn by loading the nodes file and try to bind
4664 * to all addresses one at a time until the ip address is found.
4666 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4668 struct ctdb_node_map *nodemap;
4671 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4672 if (nodemap == NULL) {
4676 for (i=0; i<nodemap->num; i++) {
4677 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4680 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4682 *pnn = nodemap->node[i].pnn;
4684 talloc_free(nodemap);
4689 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4690 talloc_free(nodemap);
4694 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4695 int argc, const char **argv)
4697 const char *reclock;
4701 usage("getreclock");
4704 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4705 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4710 if (reclock != NULL) {
4711 printf("%s\n", reclock);
4717 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4718 struct ctdb_context *ctdb,
4719 int argc, const char **argv)
4721 uint32_t lmasterrole = 0;
4725 usage("setlmasterrole");
4728 if (strcmp(argv[0], "on") == 0) {
4730 } else if (strcmp(argv[0], "off") == 0) {
4733 usage("setlmasterrole");
4736 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4737 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4745 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4746 struct ctdb_context *ctdb,
4747 int argc, const char **argv)
4749 uint32_t recmasterrole = 0;
4753 usage("setrecmasterrole");
4756 if (strcmp(argv[0], "on") == 0) {
4758 } else if (strcmp(argv[0], "off") == 0) {
4761 usage("setrecmasterrole");
4764 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4765 ctdb->cmd_pnn, TIMEOUT(),
4774 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4775 struct ctdb_context *ctdb,
4776 int argc, const char **argv)
4783 usage("setdbreadonly");
4786 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4790 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4791 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4795 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4796 ctdb->cmd_pnn, TIMEOUT(), db_id);
4804 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4805 int argc, const char **argv)
4812 usage("setdbsticky");
4815 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4819 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4820 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4824 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4825 ctdb->cmd_pnn, TIMEOUT(), db_id);
4833 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4834 int argc, const char **argv)
4836 const char *db_name;
4837 struct ctdb_db_context *db;
4838 struct ctdb_transaction_handle *h;
4843 if (argc < 2 || argc > 3) {
4847 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4852 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4853 fprintf(stderr, "Transactions not supported on DB %s\n",
4858 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4861 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4865 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4867 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4871 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4872 TIMEOUT(), db, true, &h);
4874 fprintf(stderr, "Failed to start transaction on db %s\n",
4879 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4881 fprintf(stderr, "Failed to read record for key %s\n",
4883 ctdb_transaction_cancel(h);
4887 printf("%.*s\n", (int)data.dsize, data.dptr);
4889 ctdb_transaction_cancel(h);
4893 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4894 int argc, const char **argv)
4896 const char *db_name;
4897 struct ctdb_db_context *db;
4898 struct ctdb_transaction_handle *h;
4907 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4912 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4913 fprintf(stderr, "Transactions not supported on DB %s\n",
4918 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4921 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4925 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4927 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4931 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4933 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4937 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4938 TIMEOUT(), db, false, &h);
4940 fprintf(stderr, "Failed to start transaction on db %s\n",
4945 ret = ctdb_transaction_store_record(h, key, data);
4947 fprintf(stderr, "Failed to store record for key %s\n",
4949 ctdb_transaction_cancel(h);
4953 ret = ctdb_transaction_commit(h);
4955 fprintf(stderr, "Failed to commit transaction on db %s\n",
4957 ctdb_transaction_cancel(h);
4964 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4965 int argc, const char **argv)
4967 const char *db_name;
4968 struct ctdb_db_context *db;
4969 struct ctdb_transaction_handle *h;
4978 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4983 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4984 fprintf(stderr, "Transactions not supported on DB %s\n",
4989 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4992 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4996 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4998 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5002 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5003 TIMEOUT(), db, false, &h);
5005 fprintf(stderr, "Failed to start transaction on db %s\n",
5010 ret = ctdb_transaction_delete_record(h, key);
5012 fprintf(stderr, "Failed to delete record for key %s\n",
5014 ctdb_transaction_cancel(h);
5018 ret = ctdb_transaction_commit(h);
5020 fprintf(stderr, "Failed to commit transaction on db %s\n",
5022 ctdb_transaction_cancel(h);
5029 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5037 /* Skip whitespace */
5038 n = strspn(*ptr, " \t");
5042 /* Quoted ASCII string - no wide characters! */
5044 n = strcspn(t, "\"");
5047 ret = str_to_data(t, n, mem_ctx, data);
5054 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5058 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5065 #define MAX_LINE_SIZE 1024
5067 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5068 TDB_DATA *key, TDB_DATA *value)
5070 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5074 ptr = fgets(line, MAX_LINE_SIZE, file);
5080 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5081 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5082 /* Line Ignored but not EOF */
5088 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5090 /* Line Ignored but not EOF */
5091 talloc_free(key->dptr);
5099 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5100 int argc, const char **argv)
5102 const char *db_name;
5103 struct ctdb_db_context *db;
5104 struct ctdb_transaction_handle *h;
5107 TDB_DATA key, value;
5110 if (argc < 1 || argc > 2) {
5114 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5119 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5120 fprintf(stderr, "Transactions not supported on DB %s\n",
5126 file = fopen(argv[1], "r");
5128 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5135 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5138 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5142 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5143 TIMEOUT(), db, false, &h);
5145 fprintf(stderr, "Failed to start transaction on db %s\n",
5150 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5151 if (key.dsize != 0) {
5152 ret = ctdb_transaction_store_record(h, key, value);
5154 fprintf(stderr, "Failed to store record\n");
5155 ctdb_transaction_cancel(h);
5158 talloc_free(key.dptr);
5159 talloc_free(value.dptr);
5163 ret = ctdb_transaction_commit(h);
5165 fprintf(stderr, "Failed to commit transaction on db %s\n",
5167 ctdb_transaction_cancel(h);
5171 if (file != stdin) {
5177 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5178 int argc, const char **argv)
5180 struct tdb_context *tdb;
5182 struct ctdb_ltdb_header header;
5185 if (argc < 2 || argc > 3) {
5189 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5191 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5195 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5197 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5202 data = tdb_fetch(tdb, key);
5203 if (data.dptr == NULL) {
5204 fprintf(stderr, "No record for key %s\n", argv[1]);
5209 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5210 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5221 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5223 fprintf(stderr, "Failed to open output file %s\n",
5228 nwritten = sys_write(fd, data.dptr, data.dsize);
5229 if (nwritten != data.dsize) {
5230 fprintf(stderr, "Failed to write record to file\n");
5239 ret = ctdb_ltdb_header_extract(&data, &header);
5241 fprintf(stderr, "Failed to parse header from data\n");
5245 dump_ltdb_header(&header);
5246 dump_tdb_data("data", data);
5251 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5252 int argc, const char **argv)
5254 struct tdb_context *tdb;
5255 TDB_DATA key, data[2], value;
5256 struct ctdb_ltdb_header header;
5257 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5261 if (argc < 3 || argc > 5) {
5265 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5267 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5271 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5273 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5278 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5280 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5285 ZERO_STRUCT(header);
5288 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5291 header.dmaster = (uint32_t)atol(argv[4]);
5294 header.flags = (uint32_t)atol(argv[5]);
5297 ctdb_ltdb_header_push(&header, header_buf, &np);
5300 data[0].dptr = header_buf;
5302 data[1].dsize = value.dsize;
5303 data[1].dptr = value.dptr;
5305 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5307 fprintf(stderr, "Failed to write record %s to file %s\n",
5316 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5317 int argc, const char **argv)
5319 const char *db_name;
5320 struct ctdb_db_context *db;
5321 struct ctdb_record_handle *h;
5324 bool readonly = false;
5327 if (argc < 2 || argc > 3) {
5332 if (strcmp(argv[2], "readonly") == 0) {
5339 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5343 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5344 fprintf(stderr, "DB %s is not a volatile database\n",
5349 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5352 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5356 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5358 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5362 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5363 db, key, readonly, &h, NULL, &data);
5365 fprintf(stderr, "Failed to read record for key %s\n",
5368 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5369 (int)data.dsize, data.dptr);
5376 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5377 int argc, const char **argv)
5379 const char *db_name;
5380 struct ctdb_db_context *db;
5381 struct ctdb_record_handle *h;
5390 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5394 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5395 fprintf(stderr, "DB %s is not a volatile database\n",
5400 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5403 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5407 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5409 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5413 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5415 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5419 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5420 db, key, false, &h, NULL, NULL);
5422 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5426 ret = ctdb_store_record(h, data);
5428 fprintf(stderr, "Failed to store record for key %s\n",
5436 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5437 int argc, const char **argv)
5439 const char *db_name;
5440 struct ctdb_db_context *db;
5441 struct ctdb_record_handle *h;
5450 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5454 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5455 fprintf(stderr, "DB %s is not a volatile database\n",
5460 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5463 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5467 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5469 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5473 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5474 db, key, false, &h, NULL, &data);
5476 fprintf(stderr, "Failed to fetch record for key %s\n",
5481 ret = ctdb_delete_record(h);
5483 fprintf(stderr, "Failed to delete record for key %s\n",
5491 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5492 int argc, const char **argv)
5494 struct sockaddr_in sin;
5500 usage("chktcpport");
5503 port = atoi(argv[0]);
5505 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5507 fprintf(stderr, "Failed to open local socket\n");
5511 v = fcntl(s, F_GETFL, 0);
5512 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5513 fprintf(stderr, "Unable to set socket non-blocking\n");
5518 bzero(&sin, sizeof(sin));
5519 sin.sin_family = AF_INET;
5520 sin.sin_port = htons(port);
5521 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5524 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5531 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5532 int argc, const char **argv)
5535 const char *db_name;
5540 usage("getdbseqnum");
5543 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5547 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5548 ctdb->cmd_pnn, TIMEOUT(), db_id,
5551 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5556 printf("0x%"PRIx64"\n", seqnum);
5560 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5561 int argc, const char **argv)
5563 const char *nodestring = NULL;
5564 struct ctdb_node_map *nodemap;
5566 bool print_hdr = false;
5569 usage("nodestatus");
5573 nodestring = argv[0];
5574 if (strcmp(nodestring, "all") == 0) {
5579 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5583 if (options.machinereadable) {
5584 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5586 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5590 for (i=0; i<nodemap->num; i++) {
5591 ret |= nodemap->node[i].flags;
5600 } db_stats_fields[] = {
5601 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5602 DBSTATISTICS_FIELD(db_ro_delegations),
5603 DBSTATISTICS_FIELD(db_ro_revokes),
5604 DBSTATISTICS_FIELD(locks.num_calls),
5605 DBSTATISTICS_FIELD(locks.num_current),
5606 DBSTATISTICS_FIELD(locks.num_pending),
5607 DBSTATISTICS_FIELD(locks.num_failed),
5608 DBSTATISTICS_FIELD(db_ro_delegations),
5611 static void print_dbstatistics(const char *db_name,
5612 struct ctdb_db_statistics *s)
5615 const char *prefix = NULL;
5618 printf("DB Statistics %s\n", db_name);
5620 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5621 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5622 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5624 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5625 prefix = db_stats_fields[i].name;
5626 printf(" %*.*s\n", preflen-1, preflen-1,
5627 db_stats_fields[i].name);
5632 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5633 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5634 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5637 printf(" hop_count_buckets:");
5638 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5639 printf(" %d", s->hop_count_bucket[i]);
5643 printf(" lock_buckets:");
5644 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5645 printf(" %d", s->locks.buckets[i]);
5649 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5650 "locks_latency MIN/AVG/MAX",
5651 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5652 s->locks.latency.max, s->locks.latency.num);
5654 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5655 "vacuum_latency MIN/AVG/MAX",
5656 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5657 s->vacuum.latency.max, s->vacuum.latency.num);
5659 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5660 for (i=0; i<s->num_hot_keys; i++) {
5662 printf(" Count:%d Key:", s->hot_keys[i].count);
5663 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5664 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5670 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5671 int argc, const char **argv)
5674 const char *db_name;
5675 struct ctdb_db_statistics *dbstats;
5679 usage("dbstatistics");
5682 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5686 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5687 ctdb->cmd_pnn, TIMEOUT(), db_id,
5690 fprintf(stderr, "Failed to get statistics for DB %s\n",
5695 print_dbstatistics(db_name, dbstats);
5699 struct disable_takeover_runs_state {
5707 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5710 struct disable_takeover_runs_state *state =
5711 (struct disable_takeover_runs_state *)private_data;
5714 if (data.dsize != sizeof(int)) {
5719 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5720 ret = *(int *)data.dptr;
5722 state->status = ret;
5726 for (i=0; i<state->node_count; i++) {
5727 if (state->pnn_list[i] == ret) {
5728 state->reply[i] = true;
5734 for (i=0; i<state->node_count; i++) {
5735 if (! state->reply[i]) {
5736 state->done = false;
5742 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5743 struct ctdb_context *ctdb, uint32_t timeout,
5744 uint32_t *pnn_list, int count)
5746 struct ctdb_disable_message disable = { 0 };
5747 struct disable_takeover_runs_state state;
5750 disable.pnn = ctdb->pnn;
5751 disable.srvid = next_srvid(ctdb);
5752 disable.timeout = timeout;
5754 state.pnn_list = pnn_list;
5755 state.node_count = count;
5758 state.reply = talloc_zero_array(mem_ctx, bool, count);
5759 if (state.reply == NULL) {
5763 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5765 disable_takeover_run_handler,
5771 for (i=0; i<count; i++) {
5772 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5781 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5783 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5785 ret = (state.status >= 0 ? 0 : 1);
5789 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5790 disable.srvid, &state);
5794 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5795 int argc, const char **argv)
5797 const char *nodestring = NULL;
5798 struct ctdb_node_map *nodemap, *nodemap2;
5799 struct ctdb_req_control request;
5800 uint32_t *pnn_list, *pnn_list2;
5801 int ret, count, count2;
5808 nodestring = argv[0];
5811 nodemap = get_nodemap(ctdb, false);
5812 if (nodemap == NULL) {
5816 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5820 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5821 mem_ctx, &pnn_list);
5823 fprintf(stderr, "Memory allocation error\n");
5827 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5828 mem_ctx, &pnn_list2);
5830 fprintf(stderr, "Memory allocation error\n");
5834 /* Disable takeover runs on all connected nodes. A reply
5835 * indicating success is needed from each node so all nodes
5836 * will need to be active.
5838 * A check could be added to not allow reloading of IPs when
5839 * there are disconnected nodes. However, this should
5840 * probably be left up to the administrator.
5842 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5845 fprintf(stderr, "Failed to disable takeover runs\n");
5849 /* Now tell all the desired nodes to reload their public IPs.
5850 * Keep trying this until it succeeds. This assumes all
5851 * failures are transient, which might not be true...
5853 ctdb_req_control_reload_public_ips(&request);
5854 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5855 pnn_list2, count2, TIMEOUT(),
5856 &request, NULL, NULL);
5858 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5861 /* It isn't strictly necessary to wait until takeover runs are
5862 * re-enabled but doing so can't hurt.
5864 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5866 fprintf(stderr, "Failed to enable takeover runs\n");
5870 return ipreallocate(mem_ctx, ctdb);
5873 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5874 int argc, const char **argv)
5876 ctdb_sock_addr addr;
5883 if (! parse_ip(argv[0], NULL, 0, &addr)) {
5884 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
5888 iface = ctdb_sys_find_ifname(&addr);
5889 if (iface == NULL) {
5890 fprintf(stderr, "Failed to find interface for IP %s\n",
5900 static const struct ctdb_cmd {
5902 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5903 bool without_daemon; /* can be run without daemon running ? */
5904 bool remote; /* can be run on remote nodes */
5907 } ctdb_commands[] = {
5908 { "version", control_version, true, false,
5909 "show version of ctdb", NULL },
5910 { "status", control_status, false, true,
5911 "show node status", NULL },
5912 { "uptime", control_uptime, false, true,
5913 "show node uptime", NULL },
5914 { "ping", control_ping, false, true,
5915 "ping all nodes", NULL },
5916 { "runstate", control_runstate, false, true,
5917 "get/check runstate of a node",
5918 "[setup|first_recovery|startup|running]" },
5919 { "getvar", control_getvar, false, true,
5920 "get a tunable variable", "<name>" },
5921 { "setvar", control_setvar, false, true,
5922 "set a tunable variable", "<name> <value>" },
5923 { "listvars", control_listvars, false, true,
5924 "list tunable variables", NULL },
5925 { "statistics", control_statistics, false, true,
5926 "show ctdb statistics", NULL },
5927 { "statisticsreset", control_statistics_reset, false, true,
5928 "reset ctdb statistics", NULL },
5929 { "stats", control_stats, false, true,
5930 "show rolling statistics", "[count]" },
5931 { "ip", control_ip, false, true,
5932 "show public ips", "[all]" },
5933 { "ipinfo", control_ipinfo, false, true,
5934 "show public ip details", "<ip>" },
5935 { "ifaces", control_ifaces, false, true,
5936 "show interfaces", NULL },
5937 { "setifacelink", control_setifacelink, false, true,
5938 "set interface link status", "<iface> up|down" },
5939 { "process-exists", control_process_exists, false, true,
5940 "check if a process exists on a node", "<pid>" },
5941 { "getdbmap", control_getdbmap, false, true,
5942 "show attached databases", NULL },
5943 { "getdbstatus", control_getdbstatus, false, true,
5944 "show database status", "<dbname|dbid>" },
5945 { "catdb", control_catdb, false, false,
5946 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5947 { "cattdb", control_cattdb, false, false,
5948 "dump local ctdb database", "<dbname|dbid>" },
5949 { "getmonmode", control_getmonmode, false, true,
5950 "show monitoring mode", NULL },
5951 { "getcapabilities", control_getcapabilities, false, true,
5952 "show node capabilities", NULL },
5953 { "pnn", control_pnn, false, false,
5954 "show the pnn of the currnet node", NULL },
5955 { "lvs", control_lvs, false, false,
5956 "show lvs configuration", "master|list|status" },
5957 { "disablemonitor", control_disable_monitor, false, true,
5958 "disable monitoring", NULL },
5959 { "enablemonitor", control_enable_monitor, false, true,
5960 "enable monitoring", NULL },
5961 { "setdebug", control_setdebug, false, true,
5962 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5963 { "getdebug", control_getdebug, false, true,
5964 "get debug level", NULL },
5965 { "attach", control_attach, false, false,
5966 "attach a database", "<dbname> [persistent|replicated]" },
5967 { "detach", control_detach, false, false,
5968 "detach database(s)", "<dbname|dbid> ..." },
5969 { "dumpmemory", control_dumpmemory, false, true,
5970 "dump ctdbd memory map", NULL },
5971 { "rddumpmemory", control_rddumpmemory, false, true,
5972 "dump recoverd memory map", NULL },
5973 { "getpid", control_getpid, false, true,
5974 "get ctdbd process ID", NULL },
5975 { "disable", control_disable, false, true,
5976 "disable a node", NULL },
5977 { "enable", control_enable, false, true,
5978 "enable a node", NULL },
5979 { "stop", control_stop, false, true,
5980 "stop a node", NULL },
5981 { "continue", control_continue, false, true,
5982 "continue a stopped node", NULL },
5983 { "ban", control_ban, false, true,
5984 "ban a node", "<bantime>"},
5985 { "unban", control_unban, false, true,
5986 "unban a node", NULL },
5987 { "shutdown", control_shutdown, false, true,
5988 "shutdown ctdb daemon", NULL },
5989 { "recover", control_recover, false, true,
5990 "force recovery", NULL },
5991 { "sync", control_ipreallocate, false, true,
5992 "run ip reallocation (deprecated)", NULL },
5993 { "ipreallocate", control_ipreallocate, false, true,
5994 "run ip reallocation", NULL },
5995 { "isnotrecmaster", control_isnotrecmaster, false, false,
5996 "check if local node is the recmaster", NULL },
5997 { "gratarp", control_gratarp, false, true,
5998 "send a gratuitous arp", "<ip> <interface>" },
5999 { "tickle", control_tickle, true, false,
6000 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6001 { "gettickles", control_gettickles, false, true,
6002 "get the list of tickles", "<ip> [<port>]" },
6003 { "addtickle", control_addtickle, false, true,
6004 "add a tickle", "<ip>:<port> <ip>:<port>" },
6005 { "deltickle", control_deltickle, false, true,
6006 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6007 { "listnodes", control_listnodes, true, true,
6008 "list nodes in the cluster", NULL },
6009 { "reloadnodes", control_reloadnodes, false, false,
6010 "reload the nodes file all nodes", NULL },
6011 { "moveip", control_moveip, false, false,
6012 "move an ip address to another node", "<ip> <node>" },
6013 { "addip", control_addip, false, true,
6014 "add an ip address to a node", "<ip/mask> <iface>" },
6015 { "delip", control_delip, false, true,
6016 "delete an ip address from a node", "<ip>" },
6017 { "backupdb", control_backupdb, false, false,
6018 "backup a database into a file", "<dbname|dbid> <file>" },
6019 { "restoredb", control_restoredb, false, false,
6020 "restore a database from a file", "<file> [dbname]" },
6021 { "dumpdbbackup", control_dumpdbbackup, true, false,
6022 "dump database from a backup file", "<file>" },
6023 { "wipedb", control_wipedb, false, false,
6024 "wipe the contents of a database.", "<dbname|dbid>"},
6025 { "recmaster", control_recmaster, false, true,
6026 "show the pnn for the recovery master", NULL },
6027 { "event", control_event, true, false,
6028 "event and event script commands", NULL },
6029 { "scriptstatus", control_scriptstatus, true, false,
6030 "show event script status",
6031 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6032 { "natgw", control_natgw, false, false,
6033 "show natgw configuration", "master|list|status" },
6034 { "getreclock", control_getreclock, false, true,
6035 "get recovery lock file", NULL },
6036 { "setlmasterrole", control_setlmasterrole, false, true,
6037 "set LMASTER role", "on|off" },
6038 { "setrecmasterrole", control_setrecmasterrole, false, true,
6039 "set RECMASTER role", "on|off"},
6040 { "setdbreadonly", control_setdbreadonly, false, true,
6041 "enable readonly records", "<dbname|dbid>" },
6042 { "setdbsticky", control_setdbsticky, false, true,
6043 "enable sticky records", "<dbname|dbid>"},
6044 { "pfetch", control_pfetch, false, false,
6045 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6046 { "pstore", control_pstore, false, false,
6047 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6048 { "pdelete", control_pdelete, false, false,
6049 "delete record from persistent database", "<dbname|dbid> <key>" },
6050 { "ptrans", control_ptrans, false, false,
6051 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6052 { "tfetch", control_tfetch, false, true,
6053 "fetch a record", "<tdb-file> <key> [<file>]" },
6054 { "tstore", control_tstore, false, true,
6055 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6056 { "readkey", control_readkey, false, false,
6057 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6058 { "writekey", control_writekey, false, false,
6059 "write value for a database key", "<dbname|dbid> <key> <value>" },
6060 { "deletekey", control_deletekey, false, false,
6061 "delete a database key", "<dbname|dbid> <key>" },
6062 { "checktcpport", control_checktcpport, true, false,
6063 "check if a service is bound to a specific tcp port or not", "<port>" },
6064 { "getdbseqnum", control_getdbseqnum, false, false,
6065 "get database sequence number", "<dbname|dbid>" },
6066 { "nodestatus", control_nodestatus, false, true,
6067 "show and return node status", "[all|<pnn-list>]" },
6068 { "dbstatistics", control_dbstatistics, false, true,
6069 "show database statistics", "<dbname|dbid>" },
6070 { "reloadips", control_reloadips, false, false,
6071 "reload the public addresses file", "[all|<pnn-list>]" },
6072 { "ipiface", control_ipiface, true, false,
6073 "Find the interface an ip address is hosted on", "<ip>" },
6076 static const struct ctdb_cmd *match_command(const char *command)
6078 const struct ctdb_cmd *cmd;
6081 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6082 cmd = &ctdb_commands[i];
6083 if (strlen(command) == strlen(cmd->name) &&
6084 strncmp(command, cmd->name, strlen(command)) == 0) {
6094 * Show usage message
6096 static void usage_full(void)
6100 poptPrintHelp(pc, stdout, 0);
6101 printf("\nCommands:\n");
6102 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6103 printf(" %-15s %-27s %s\n",
6104 ctdb_commands[i].name,
6105 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6106 ctdb_commands[i].msg);
6110 static void usage(const char *command)
6112 const struct ctdb_cmd *cmd;
6114 if (command == NULL) {
6119 cmd = match_command(command);
6123 poptPrintUsage(pc, stdout, 0);
6124 printf("\nCommands:\n");
6125 printf(" %-15s %-27s %s\n",
6126 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6132 struct poptOption cmdline_options[] = {
6134 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6135 "CTDB socket path", "filename" },
6136 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6138 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6139 "timelimit (in seconds)" },
6140 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6141 "node specification - integer" },
6142 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6143 "enable machine readable output", NULL },
6144 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6145 "specify separator for machine readable output", "CHAR" },
6146 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6147 "enable machine parsable output with separator |", NULL },
6148 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6149 "enable verbose output", NULL },
6150 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6151 "die if runtime exceeds this limit (in seconds)" },
6155 static int process_command(const struct ctdb_cmd *cmd, int argc,
6158 TALLOC_CTX *tmp_ctx;
6159 struct ctdb_context *ctdb;
6162 uint64_t srvid_offset;
6164 tmp_ctx = talloc_new(NULL);
6165 if (tmp_ctx == NULL) {
6166 fprintf(stderr, "Memory allocation error\n");
6170 if (cmd->without_daemon) {
6171 if (options.pnn != -1) {
6173 "Cannot specify node for command %s\n",
6178 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6179 talloc_free(tmp_ctx);
6183 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6185 fprintf(stderr, "Memory allocation error\n");
6189 ctdb->ev = tevent_context_init(ctdb);
6190 if (ctdb->ev == NULL) {
6191 fprintf(stderr, "Failed to initialize tevent\n");
6195 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6197 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6200 if (!find_node_xpnn(ctdb, NULL)) {
6201 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6206 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6207 srvid_offset = getpid() & 0xFFFF;
6208 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6210 if (options.pnn != -1) {
6211 status = verify_pnn(ctdb, options.pnn);
6216 ctdb->cmd_pnn = options.pnn;
6218 ctdb->cmd_pnn = ctdb->pnn;
6221 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6222 fprintf(stderr, "Node cannot be specified for command %s\n",
6227 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6228 talloc_free(tmp_ctx);
6232 talloc_free(tmp_ctx);
6236 static void signal_handler(int sig)
6238 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6241 static void alarm_handler(int sig)
6243 /* Kill any child processes */
6244 signal(SIGTERM, signal_handler);
6250 int main(int argc, const char *argv[])
6253 const char **extra_argv;
6255 const struct ctdb_cmd *cmd;
6256 const char *ctdb_socket;
6262 /* Set default options */
6263 options.socket = CTDB_SOCKET;
6264 options.debuglevelstr = NULL;
6265 options.timelimit = 10;
6267 options.maxruntime = 0;
6270 ctdb_socket = getenv("CTDB_SOCKET");
6271 if (ctdb_socket != NULL) {
6272 options.socket = ctdb_socket;
6275 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6276 POPT_CONTEXT_KEEP_FIRST);
6277 while ((opt = poptGetNextOpt(pc)) != -1) {
6278 fprintf(stderr, "Invalid option %s: %s\n",
6279 poptBadOption(pc, 0), poptStrerror(opt));
6283 if (options.maxruntime == 0) {
6284 const char *ctdb_timeout;
6286 ctdb_timeout = getenv("CTDB_TIMEOUT");
6287 if (ctdb_timeout != NULL) {
6288 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6290 options.maxruntime = 120;
6293 if (options.maxruntime <= 120) {
6294 /* default timeout is 120 seconds */
6295 options.maxruntime = 120;
6298 if (options.machineparsable) {
6299 options.machinereadable = 1;
6302 /* setup the remaining options for the commands */
6304 extra_argv = poptGetArgs(pc);
6307 while (extra_argv[extra_argc]) extra_argc++;
6310 if (extra_argc < 1) {
6314 cmd = match_command(extra_argv[0]);
6316 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6320 /* Enable logging */
6321 setup_logging("ctdb", DEBUG_STDERR);
6322 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6323 DEBUGLEVEL = loglevel;
6325 DEBUGLEVEL = DEBUG_ERR;
6328 signal(SIGALRM, alarm_handler);
6329 alarm(options.maxruntime);
6331 ret = process_command(cmd, extra_argc, extra_argv);
6336 (void)poptFreeContext(pc);