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 "common/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 "protocol/protocol_util.h"
43 #include "common/system_socket.h"
44 #include "client/client.h"
45 #include "client/client_sync.h"
47 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
49 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
50 #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;
386 ret = ctdb_sock_addr_from_string(nstr, &addr, false);
388 fprintf(stderr, "Invalid IP address %s\n", nstr);
393 nodemap->node = talloc_realloc(nodemap, nodemap->node,
394 struct ctdb_node_and_flags, num+1);
395 if (nodemap->node == NULL) {
399 n = &nodemap->node[num];
404 nodemap->num = num+1;
408 /* Read a nodes file into a node map */
409 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
415 struct ctdb_node_map *nodemap;
417 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
418 if (nodemap == NULL) {
422 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
427 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
431 for (i=0; i<nlines; i++) {
437 /* strip leading spaces */
438 while((*node == ' ') || (*node == '\t')) {
444 /* strip trailing spaces */
446 ((node[len-1] == ' ') || (node[len-1] == '\t')))
456 /* A "deleted" node is a node that is
457 commented out in the nodes file. This is
458 used instead of removing a line, which
459 would cause subsequent nodes to change
461 flags = NODE_FLAGS_DELETED;
462 node = discard_const("0.0.0.0");
466 if (! node_map_add(nodemap, node, flags)) {
468 TALLOC_FREE(nodemap);
477 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
479 struct ctdb_node_map *nodemap;
480 const char *nodes_list = NULL;
482 const char *basedir = getenv("CTDB_BASE");
483 if (basedir == NULL) {
484 basedir = CTDB_ETCDIR;
486 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
487 if (nodes_list == NULL) {
488 fprintf(stderr, "Memory allocation error\n");
492 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
493 if (nodemap == NULL) {
494 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
502 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
503 struct ctdb_context *ctdb,
504 struct ctdb_dbid_map *dbmap,
507 struct ctdb_dbid *db = NULL;
511 for (i=0; i<dbmap->num; i++) {
512 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
513 ctdb->pnn, TIMEOUT(),
514 dbmap->dbs[i].db_id, &name);
519 if (strcmp(db_name, name) == 0) {
520 talloc_free(discard_const(name));
529 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
530 const char *db_arg, uint32_t *db_id,
531 const char **db_name, uint8_t *db_flags)
533 struct ctdb_dbid_map *dbmap;
534 struct ctdb_dbid *db = NULL;
536 const char *name = NULL;
539 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
540 ctdb->pnn, TIMEOUT(), &dbmap);
545 if (strncmp(db_arg, "0x", 2) == 0) {
546 id = strtoul(db_arg, NULL, 0);
547 for (i=0; i<dbmap->num; i++) {
548 if (id == dbmap->dbs[i].db_id) {
555 db = db_find(mem_ctx, ctdb, dbmap, name);
559 fprintf(stderr, "No database matching '%s' found\n", db_arg);
564 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
565 ctdb->pnn, TIMEOUT(), id, &name);
574 if (db_name != NULL) {
575 *db_name = talloc_strdup(mem_ctx, name);
577 if (db_flags != NULL) {
578 *db_flags = db->flags;
583 static int h2i(char h)
585 if (h >= 'a' && h <= 'f') {
588 if (h >= 'A' && h <= 'F') {
594 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
601 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
606 data.dsize = len / 2;
607 data.dptr = talloc_size(mem_ctx, data.dsize);
608 if (data.dptr == NULL) {
612 for (i=0; i<data.dsize; i++) {
613 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
620 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
626 if (strncmp(str, "0x", 2) == 0) {
627 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
629 data.dptr = talloc_memdup(mem_ctx, str, len);
630 if (data.dptr == NULL) {
640 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
641 const char *path, int argc, const char **argv)
644 int save_errno, status, ret;
645 const char **new_argv;
648 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
649 if (new_argv == NULL) {
654 for (i=0; i<argc; i++) {
655 new_argv[i+1] = argv[i];
657 new_argv[argc+1] = NULL;
662 talloc_free(new_argv);
663 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
664 command, path, strerror(save_errno));
669 ret = execv(path, discard_const(new_argv));
673 /* Should not happen */
677 talloc_free(new_argv);
679 ret = waitpid(pid, &status, 0);
682 fprintf(stderr, "waitpid() failed for %s - %s\n",
683 command, strerror(save_errno));
687 if (WIFEXITED(status)) {
688 int pstatus = WEXITSTATUS(status);
689 if (WIFSIGNALED(status)) {
690 fprintf(stderr, "%s terminated with signal %d\n",
691 command, WTERMSIG(status));
693 } else if (pstatus >= 64 && pstatus < 255) {
694 fprintf(stderr, "%s failed with error %d\n",
695 command, pstatus-64);
701 } else if (WIFSIGNALED(status)) {
702 fprintf(stderr, "%s terminated with signal %d\n",
703 command, WTERMSIG(status));
714 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
715 int argc, const char **argv)
717 printf("%s\n", ctdb_version_string);
721 static bool partially_online(TALLOC_CTX *mem_ctx,
722 struct ctdb_context *ctdb,
723 struct ctdb_node_and_flags *node)
725 struct ctdb_iface_list *iface_list;
729 if (node->flags != 0) {
733 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
734 node->pnn, TIMEOUT(), &iface_list);
740 for (i=0; i < iface_list->num; i++) {
741 if (iface_list->iface[i].link_state == 0) {
750 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
751 struct ctdb_context *ctdb,
752 struct ctdb_node_map *nodemap,
755 struct ctdb_node_and_flags *node;
758 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
762 "Disconnected", options.sep,
763 "Banned", options.sep,
764 "Disabled", options.sep,
765 "Unhealthy", options.sep,
766 "Stopped", options.sep,
767 "Inactive", options.sep,
768 "PartiallyOnline", options.sep,
769 "ThisNode", options.sep);
771 for (i=0; i<nodemap->num; i++) {
772 node = &nodemap->node[i];
773 if (node->flags & NODE_FLAGS_DELETED) {
777 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
779 node->pnn, options.sep,
780 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
782 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
783 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
784 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
786 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
787 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
788 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
789 partially_online(mem_ctx, ctdb, node), options.sep,
790 (node->pnn == mypnn)?'Y':'N', options.sep);
795 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
796 struct ctdb_node_map *nodemap, uint32_t mypnn,
799 struct ctdb_node_and_flags *node;
800 int num_deleted_nodes = 0;
803 for (i=0; i<nodemap->num; i++) {
804 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
810 if (num_deleted_nodes == 0) {
811 printf("Number of nodes:%d\n", nodemap->num);
813 printf("Number of nodes:%d "
814 "(including %d deleted nodes)\n",
815 nodemap->num, num_deleted_nodes);
819 for (i=0; i<nodemap->num; i++) {
820 node = &nodemap->node[i];
821 if (node->flags & NODE_FLAGS_DELETED) {
825 printf("pnn:%u %-16s %s%s\n",
827 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
828 partially_online(mem_ctx, ctdb, node) ?
830 pretty_print_flags(mem_ctx, node->flags),
831 node->pnn == mypnn ? " (THIS NODE)" : "");
835 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
836 struct ctdb_node_map *nodemap, uint32_t mypnn,
837 struct ctdb_vnn_map *vnnmap, int recmode,
842 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
844 if (vnnmap->generation == INVALID_GENERATION) {
845 printf("Generation:INVALID\n");
847 printf("Generation:%u\n", vnnmap->generation);
849 printf("Size:%d\n", vnnmap->size);
850 for (i=0; i<vnnmap->size; i++) {
851 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
854 printf("Recovery mode:%s (%d)\n",
855 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
857 printf("Recovery master:%d\n", recmaster);
860 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
861 int argc, const char **argv)
863 struct ctdb_node_map *nodemap;
864 struct ctdb_vnn_map *vnnmap;
873 nodemap = get_nodemap(ctdb, false);
874 if (nodemap == NULL) {
878 if (options.machinereadable == 1) {
879 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
883 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
884 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
889 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
890 ctdb->cmd_pnn, TIMEOUT(), &recmode);
895 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
896 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
901 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
906 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
907 int argc, const char **argv)
909 struct ctdb_uptime *uptime;
910 int ret, tmp, days, hours, minutes, seconds;
912 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
913 ctdb->cmd_pnn, TIMEOUT(), &uptime);
918 printf("Current time of node %-4u : %s",
919 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
921 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
922 seconds = tmp % 60; tmp /= 60;
923 minutes = tmp % 60; tmp /= 60;
924 hours = tmp % 24; tmp /= 24;
927 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
928 days, hours, minutes, seconds,
929 ctime(&uptime->ctdbd_start_time.tv_sec));
931 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
932 seconds = tmp % 60; tmp /= 60;
933 minutes = tmp % 60; tmp /= 60;
934 hours = tmp % 24; tmp /= 24;
937 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
938 days, hours, minutes, seconds,
939 ctime(&uptime->last_recovery_finished.tv_sec));
941 printf("Duration of last recovery/failover: %lf seconds\n",
942 timeval_delta(&uptime->last_recovery_finished,
943 &uptime->last_recovery_started));
948 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
949 int argc, const char **argv)
952 int ret, num_clients;
954 tv = timeval_current();
955 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
956 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
961 printf("response from %u time=%.6f sec (%d clients)\n",
962 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
966 const char *runstate_to_string(enum ctdb_runstate runstate);
967 enum ctdb_runstate runstate_from_string(const char *runstate_str);
969 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
970 int argc, const char **argv)
972 enum ctdb_runstate runstate;
976 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
977 ctdb->cmd_pnn, TIMEOUT(), &runstate);
983 for (i=0; i<argc; i++) {
984 enum ctdb_runstate t;
987 t = ctdb_runstate_from_string(argv[i]);
988 if (t == CTDB_RUNSTATE_UNKNOWN) {
989 printf("Invalid run state (%s)\n", argv[i]);
1000 printf("CTDB not in required run state (got %s)\n",
1001 ctdb_runstate_to_string(runstate));
1005 printf("%s\n", ctdb_runstate_to_string(runstate));
1009 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1010 int argc, const char **argv)
1012 struct ctdb_var_list *tun_var_list;
1021 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1022 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1025 "Failed to get list of variables from node %u\n",
1031 for (i=0; i<tun_var_list->count; i++) {
1032 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1039 printf("No such tunable %s\n", argv[0]);
1043 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1044 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1049 printf("%-26s = %u\n", argv[0], value);
1053 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1054 int argc, const char **argv)
1056 struct ctdb_var_list *tun_var_list;
1057 struct ctdb_tunable tunable;
1065 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1066 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1069 "Failed to get list of variables from node %u\n",
1075 for (i=0; i<tun_var_list->count; i++) {
1076 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1083 printf("No such tunable %s\n", argv[0]);
1087 tunable.name = argv[0];
1088 tunable.value = strtoul(argv[1], NULL, 0);
1090 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1091 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1095 "Setting obsolete tunable variable '%s'\n",
1104 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1105 int argc, const char **argv)
1107 struct ctdb_var_list *tun_var_list;
1114 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1115 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1120 for (i=0; i<tun_var_list->count; i++) {
1121 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1130 } stats_fields[] = {
1131 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1132 STATISTICS_FIELD(num_clients),
1133 STATISTICS_FIELD(frozen),
1134 STATISTICS_FIELD(recovering),
1135 STATISTICS_FIELD(num_recoveries),
1136 STATISTICS_FIELD(client_packets_sent),
1137 STATISTICS_FIELD(client_packets_recv),
1138 STATISTICS_FIELD(node_packets_sent),
1139 STATISTICS_FIELD(node_packets_recv),
1140 STATISTICS_FIELD(keepalive_packets_sent),
1141 STATISTICS_FIELD(keepalive_packets_recv),
1142 STATISTICS_FIELD(node.req_call),
1143 STATISTICS_FIELD(node.reply_call),
1144 STATISTICS_FIELD(node.req_dmaster),
1145 STATISTICS_FIELD(node.reply_dmaster),
1146 STATISTICS_FIELD(node.reply_error),
1147 STATISTICS_FIELD(node.req_message),
1148 STATISTICS_FIELD(node.req_control),
1149 STATISTICS_FIELD(node.reply_control),
1150 STATISTICS_FIELD(node.req_tunnel),
1151 STATISTICS_FIELD(client.req_call),
1152 STATISTICS_FIELD(client.req_message),
1153 STATISTICS_FIELD(client.req_control),
1154 STATISTICS_FIELD(client.req_tunnel),
1155 STATISTICS_FIELD(timeouts.call),
1156 STATISTICS_FIELD(timeouts.control),
1157 STATISTICS_FIELD(timeouts.traverse),
1158 STATISTICS_FIELD(locks.num_calls),
1159 STATISTICS_FIELD(locks.num_current),
1160 STATISTICS_FIELD(locks.num_pending),
1161 STATISTICS_FIELD(locks.num_failed),
1162 STATISTICS_FIELD(total_calls),
1163 STATISTICS_FIELD(pending_calls),
1164 STATISTICS_FIELD(childwrite_calls),
1165 STATISTICS_FIELD(pending_childwrite_calls),
1166 STATISTICS_FIELD(memory_used),
1167 STATISTICS_FIELD(max_hop_count),
1168 STATISTICS_FIELD(total_ro_delegations),
1169 STATISTICS_FIELD(total_ro_revokes),
1172 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1174 static void print_statistics_machine(struct ctdb_statistics *s,
1180 printf("CTDB version%s", options.sep);
1181 printf("Current time of statistics%s", options.sep);
1182 printf("Statistics collected since%s", options.sep);
1183 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1184 printf("%s%s", stats_fields[i].name, options.sep);
1186 printf("num_reclock_ctdbd_latency%s", options.sep);
1187 printf("min_reclock_ctdbd_latency%s", options.sep);
1188 printf("avg_reclock_ctdbd_latency%s", options.sep);
1189 printf("max_reclock_ctdbd_latency%s", options.sep);
1191 printf("num_reclock_recd_latency%s", options.sep);
1192 printf("min_reclock_recd_latency%s", options.sep);
1193 printf("avg_reclock_recd_latency%s", options.sep);
1194 printf("max_reclock_recd_latency%s", options.sep);
1196 printf("num_call_latency%s", options.sep);
1197 printf("min_call_latency%s", options.sep);
1198 printf("avg_call_latency%s", options.sep);
1199 printf("max_call_latency%s", options.sep);
1201 printf("num_lockwait_latency%s", options.sep);
1202 printf("min_lockwait_latency%s", options.sep);
1203 printf("avg_lockwait_latency%s", options.sep);
1204 printf("max_lockwait_latency%s", options.sep);
1206 printf("num_childwrite_latency%s", options.sep);
1207 printf("min_childwrite_latency%s", options.sep);
1208 printf("avg_childwrite_latency%s", options.sep);
1209 printf("max_childwrite_latency%s", options.sep);
1213 printf("%u%s", CTDB_PROTOCOL, options.sep);
1214 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1215 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1216 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1218 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1221 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1222 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1223 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1224 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1226 printf("%u%s", s->reclock.recd.num, options.sep);
1227 printf("%.6f%s", s->reclock.recd.min, options.sep);
1228 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1229 printf("%.6f%s", s->reclock.recd.max, options.sep);
1231 printf("%d%s", s->call_latency.num, options.sep);
1232 printf("%.6f%s", s->call_latency.min, options.sep);
1233 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1234 printf("%.6f%s", s->call_latency.max, options.sep);
1236 printf("%d%s", s->childwrite_latency.num, options.sep);
1237 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1238 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1239 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1243 static void print_statistics(struct ctdb_statistics *s)
1245 int tmp, days, hours, minutes, seconds;
1247 const char *prefix = NULL;
1250 tmp = s->statistics_current_time.tv_sec -
1251 s->statistics_start_time.tv_sec;
1252 seconds = tmp % 60; tmp /= 60;
1253 minutes = tmp % 60; tmp /= 60;
1254 hours = tmp % 24; tmp /= 24;
1257 printf("CTDB version %u\n", CTDB_PROTOCOL);
1258 printf("Current time of statistics : %s",
1259 ctime(&s->statistics_current_time.tv_sec));
1260 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1261 days, hours, minutes, seconds,
1262 ctime(&s->statistics_start_time.tv_sec));
1264 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1265 if (strchr(stats_fields[i].name, '.') != NULL) {
1266 preflen = strcspn(stats_fields[i].name, ".") + 1;
1268 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1269 prefix = stats_fields[i].name;
1270 printf(" %*.*s\n", preflen-1, preflen-1,
1271 stats_fields[i].name);
1276 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1277 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1278 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1281 printf(" hop_count_buckets:");
1282 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1283 printf(" %d", s->hop_count_bucket[i]);
1286 printf(" lock_buckets:");
1287 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1288 printf(" %d", s->locks.buckets[i]);
1291 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1292 "locks_latency MIN/AVG/MAX",
1293 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1294 s->locks.latency.max, s->locks.latency.num);
1296 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1297 "reclock_ctdbd MIN/AVG/MAX",
1298 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1299 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1301 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1302 "reclock_recd MIN/AVG/MAX",
1303 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1304 s->reclock.recd.max, s->reclock.recd.num);
1306 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1307 "call_latency MIN/AVG/MAX",
1308 s->call_latency.min, LATENCY_AVG(s->call_latency),
1309 s->call_latency.max, s->call_latency.num);
1311 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1312 "childwrite_latency MIN/AVG/MAX",
1313 s->childwrite_latency.min,
1314 LATENCY_AVG(s->childwrite_latency),
1315 s->childwrite_latency.max, s->childwrite_latency.num);
1318 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1319 int argc, const char **argv)
1321 struct ctdb_statistics *stats;
1325 usage("statistics");
1328 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1329 ctdb->cmd_pnn, TIMEOUT(), &stats);
1334 if (options.machinereadable) {
1335 print_statistics_machine(stats, true);
1337 print_statistics(stats);
1343 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1344 struct ctdb_context *ctdb,
1345 int argc, const char **argv)
1350 usage("statisticsreset");
1353 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1354 ctdb->cmd_pnn, TIMEOUT());
1362 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1363 int argc, const char **argv)
1365 struct ctdb_statistics_list *slist;
1366 int ret, count = 0, i;
1367 bool show_header = true;
1374 count = atoi(argv[0]);
1377 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1378 ctdb->cmd_pnn, TIMEOUT(), &slist);
1383 for (i=0; i<slist->num; i++) {
1384 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1387 if (options.machinereadable == 1) {
1388 print_statistics_machine(&slist->stats[i],
1390 show_header = false;
1392 print_statistics(&slist->stats[i]);
1394 if (count > 0 && i == count) {
1402 static int ctdb_public_ip_cmp(const void *a, const void *b)
1404 const struct ctdb_public_ip *ip_a = a;
1405 const struct ctdb_public_ip *ip_b = b;
1407 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1410 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1411 struct ctdb_public_ip_list *ips,
1412 struct ctdb_public_ip_info **ipinfo,
1416 char *conf, *avail, *active;
1418 if (options.machinereadable == 1) {
1419 printf("%s%s%s%s%s", options.sep,
1420 "Public IP", options.sep,
1421 "Node", options.sep);
1422 if (options.verbose == 1) {
1423 printf("%s%s%s%s%s%s\n",
1424 "ActiveInterfaces", options.sep,
1425 "AvailableInterfaces", options.sep,
1426 "ConfiguredInterfaces", options.sep);
1432 printf("Public IPs on ALL nodes\n");
1434 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1438 for (i = 0; i < ips->num; i++) {
1440 if (options.machinereadable == 1) {
1441 printf("%s%s%s%d%s", options.sep,
1442 ctdb_sock_addr_to_string(
1443 mem_ctx, &ips->ip[i].addr, false),
1445 (int)ips->ip[i].pnn, options.sep);
1447 printf("%s", ctdb_sock_addr_to_string(
1448 mem_ctx, &ips->ip[i].addr, false));
1451 if (options.verbose == 0) {
1452 if (options.machinereadable == 1) {
1455 printf(" %d\n", (int)ips->ip[i].pnn);
1464 if (ipinfo[i] == NULL) {
1468 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1469 struct ctdb_iface *iface;
1471 iface = &ipinfo[i]->ifaces->iface[j];
1473 conf = talloc_strdup(mem_ctx, iface->name);
1475 conf = talloc_asprintf_append(
1476 conf, ",%s", iface->name);
1479 if (ipinfo[i]->active_idx == j) {
1480 active = iface->name;
1483 if (iface->link_state == 0) {
1487 if (avail == NULL) {
1488 avail = talloc_strdup(mem_ctx, iface->name);
1490 avail = talloc_asprintf_append(
1491 avail, ",%s", iface->name);
1497 if (options.machinereadable == 1) {
1498 printf("%s%s%s%s%s%s\n",
1499 active ? active : "", options.sep,
1500 avail ? avail : "", options.sep,
1501 conf ? conf : "", options.sep);
1503 printf(" node[%d] active[%s] available[%s]"
1504 " configured[%s]\n",
1505 (int)ips->ip[i].pnn, active ? active : "",
1506 avail ? avail : "", conf ? conf : "");
1511 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1512 size_t datalen, void *private_data)
1514 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1515 private_data, struct ctdb_public_ip_list);
1516 struct ctdb_public_ip *ip;
1518 ip = (struct ctdb_public_ip *)databuf;
1519 ips->ip[ips->num] = *ip;
1525 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1526 struct ctdb_public_ip_list **out)
1528 struct ctdb_node_map *nodemap;
1529 struct ctdb_public_ip_list *ips;
1530 struct db_hash_context *ipdb;
1532 int ret, count, i, j;
1534 nodemap = get_nodemap(ctdb, false);
1535 if (nodemap == NULL) {
1539 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1544 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1550 for (i=0; i<count; i++) {
1551 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1552 pnn_list[i], TIMEOUT(),
1558 for (j=0; j<ips->num; j++) {
1559 struct ctdb_public_ip ip;
1561 ip.pnn = ips->ip[j].pnn;
1562 ip.addr = ips->ip[j].addr;
1564 if (pnn_list[i] == ip.pnn) {
1565 /* Node claims IP is hosted on it, so
1566 * save that information
1568 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1570 (uint8_t *)&ip, sizeof(ip));
1575 /* Node thinks IP is hosted elsewhere,
1576 * so overwrite with CTDB_UNKNOWN_PNN
1577 * if there's no existing entry
1579 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1581 if (ret == ENOENT) {
1582 ip.pnn = CTDB_UNKNOWN_PNN;
1583 ret = db_hash_add(ipdb,
1584 (uint8_t *)&ip.addr,
1598 talloc_free(pnn_list);
1600 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1605 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1610 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1611 if (ips->ip == NULL) {
1615 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1620 if (count != ips->num) {
1634 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1635 int argc, const char **argv)
1637 struct ctdb_public_ip_list *ips;
1638 struct ctdb_public_ip_info **ipinfo;
1640 bool do_all = false;
1647 if (strcmp(argv[0], "all") == 0) {
1655 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1657 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1658 ctdb->cmd_pnn, TIMEOUT(),
1665 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1666 ctdb_public_ip_cmp);
1668 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1669 if (ipinfo == NULL) {
1673 for (i=0; i<ips->num; i++) {
1676 pnn = ips->ip[i].pnn;
1678 pnn = ctdb->cmd_pnn;
1680 if (pnn == CTDB_UNKNOWN_PNN) {
1684 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1686 TIMEOUT(), &ips->ip[i].addr,
1693 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1697 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1698 int argc, const char **argv)
1700 struct ctdb_public_ip_info *ipinfo;
1701 ctdb_sock_addr addr;
1708 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
1710 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1714 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1715 ctdb->cmd_pnn, TIMEOUT(), &addr,
1719 printf("Node %u does not know about IP %s\n",
1720 ctdb->cmd_pnn, argv[0]);
1725 printf("Public IP[%s] info on node %u\n",
1726 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1729 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1730 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1731 ipinfo->ip.pnn, ipinfo->ifaces->num);
1733 for (i=0; i<ipinfo->ifaces->num; i++) {
1734 struct ctdb_iface *iface;
1736 iface = &ipinfo->ifaces->iface[i];
1737 iface->name[CTDB_IFACE_SIZE] = '\0';
1738 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1740 iface->link_state == 0 ? "down" : "up",
1742 (i == ipinfo->active_idx) ? " (active)" : "");
1748 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1749 int argc, const char **argv)
1751 struct ctdb_iface_list *ifaces;
1758 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1759 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1764 if (ifaces->num == 0) {
1765 printf("No interfaces configured on node %u\n",
1770 if (options.machinereadable) {
1771 printf("%s%s%s%s%s%s%s\n", options.sep,
1772 "Name", options.sep,
1773 "LinkStatus", options.sep,
1774 "References", options.sep);
1776 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1779 for (i=0; i<ifaces->num; i++) {
1780 if (options.machinereadable) {
1781 printf("%s%s%s%u%s%u%s\n", options.sep,
1782 ifaces->iface[i].name, options.sep,
1783 ifaces->iface[i].link_state, options.sep,
1784 ifaces->iface[i].references, options.sep);
1786 printf("name:%s link:%s references:%u\n",
1787 ifaces->iface[i].name,
1788 ifaces->iface[i].link_state ? "up" : "down",
1789 ifaces->iface[i].references);
1796 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1797 int argc, const char **argv)
1799 struct ctdb_iface_list *ifaces;
1800 struct ctdb_iface *iface;
1804 usage("setifacelink");
1807 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1808 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1812 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1813 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1816 "Failed to get interface information from node %u\n",
1822 for (i=0; i<ifaces->num; i++) {
1823 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1824 iface = &ifaces->iface[i];
1829 if (iface == NULL) {
1830 printf("Interface %s not configured on node %u\n",
1831 argv[0], ctdb->cmd_pnn);
1835 if (strcmp(argv[1], "up") == 0) {
1836 iface->link_state = 1;
1837 } else if (strcmp(argv[1], "down") == 0) {
1838 iface->link_state = 0;
1840 usage("setifacelink");
1844 iface->references = 0;
1846 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1847 ctdb->cmd_pnn, TIMEOUT(), iface);
1855 static int control_process_exists(TALLOC_CTX *mem_ctx,
1856 struct ctdb_context *ctdb,
1857 int argc, const char **argv)
1863 if (argc != 1 && argc != 2) {
1864 usage("process-exists");
1867 pid = atoi(argv[0]);
1869 srvid = strtoull(argv[1], NULL, 0);
1873 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1874 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1876 struct ctdb_pid_srvid pid_srvid;
1878 pid_srvid.pid = pid;
1879 pid_srvid.srvid = srvid;
1881 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
1882 ctdb->client, ctdb->cmd_pnn,
1883 TIMEOUT(), &pid_srvid,
1892 printf("PID %d %s\n", pid,
1893 (status == 0 ? "exists" : "does not exist"));
1895 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
1896 (status == 0 ? "exists" : "does not exist"));
1901 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1902 int argc, const char **argv)
1904 struct ctdb_dbid_map *dbmap;
1911 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1912 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1917 if (options.machinereadable == 1) {
1918 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1921 "Name", options.sep,
1922 "Path", options.sep,
1923 "Persistent", options.sep,
1924 "Sticky", options.sep,
1925 "Unhealthy", options.sep,
1926 "Readonly", options.sep,
1927 "Replicated", options.sep);
1929 printf("Number of databases:%d\n", dbmap->num);
1932 for (i=0; i<dbmap->num; i++) {
1942 db_id = dbmap->dbs[i].db_id;
1944 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1945 ctdb->cmd_pnn, TIMEOUT(), db_id,
1951 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1952 ctdb->cmd_pnn, TIMEOUT(), db_id,
1958 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1959 ctdb->cmd_pnn, TIMEOUT(), db_id,
1965 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1966 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1967 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1968 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
1970 if (options.machinereadable == 1) {
1971 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1976 !! (persistent), options.sep,
1977 !! (sticky), options.sep,
1978 !! (health), options.sep,
1979 !! (readonly), options.sep,
1980 !! (replicated), options.sep);
1982 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1984 persistent ? " PERSISTENT" : "",
1985 sticky ? " STICKY" : "",
1986 readonly ? " READONLY" : "",
1987 replicated ? " REPLICATED" : "",
1988 health ? " UNHEALTHY" : "");
1991 talloc_free(discard_const(name));
1992 talloc_free(discard_const(path));
1993 talloc_free(discard_const(health));
1999 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2000 int argc, const char **argv)
2003 const char *db_name, *db_path, *db_health;
2008 usage("getdbstatus");
2011 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2015 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2016 ctdb->cmd_pnn, TIMEOUT(), db_id,
2022 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2023 ctdb->cmd_pnn, TIMEOUT(), db_id,
2029 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2030 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2031 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2032 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2033 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2034 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2035 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2039 struct dump_record_state {
2043 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2045 static void dump_tdb_data(const char *name, TDB_DATA val)
2049 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2050 for (i=0; i<val.dsize; i++) {
2051 if (ISASCII(val.dptr[i])) {
2052 fprintf(stdout, "%c", val.dptr[i]);
2054 fprintf(stdout, "\\%02X", val.dptr[i]);
2057 fprintf(stdout, "\"\n");
2060 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2062 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2063 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2064 fprintf(stdout, "flags: 0x%08x", header->flags);
2065 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2066 fprintf(stdout, " MIGRATED_WITH_DATA");
2068 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2069 fprintf(stdout, " VACUUM_MIGRATED");
2071 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2072 fprintf(stdout, " AUTOMATIC");
2074 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2075 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2077 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2078 fprintf(stdout, " RO_HAVE_READONLY");
2080 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2081 fprintf(stdout, " RO_REVOKING_READONLY");
2083 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2084 fprintf(stdout, " RO_REVOKE_COMPLETE");
2086 fprintf(stdout, "\n");
2090 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2091 TDB_DATA key, TDB_DATA data, void *private_data)
2093 struct dump_record_state *state =
2094 (struct dump_record_state *)private_data;
2098 dump_tdb_data("key", key);
2099 dump_ltdb_header(header);
2100 dump_tdb_data("data", data);
2101 fprintf(stdout, "\n");
2106 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2107 int argc, const char **argv)
2109 struct ctdb_db_context *db;
2110 const char *db_name;
2113 struct dump_record_state state;
2120 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2124 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2127 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2133 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2134 ctdb->cmd_pnn, TIMEOUT(),
2135 dump_record, &state);
2137 printf("Dumped %u records\n", state.count);
2142 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2143 int argc, const char **argv)
2145 struct ctdb_db_context *db;
2146 const char *db_name;
2149 struct dump_record_state state;
2156 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2160 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2163 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2168 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2170 printf("Dumped %u record(s)\n", state.count);
2175 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2176 struct ctdb_context *ctdb,
2177 int argc, const char **argv)
2183 usage("getcapabilities");
2186 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2187 ctdb->cmd_pnn, TIMEOUT(), &caps);
2192 if (options.machinereadable == 1) {
2193 printf("%s%s%s%s%s\n",
2195 "RECMASTER", options.sep,
2196 "LMASTER", options.sep);
2197 printf("%s%d%s%d%s\n", options.sep,
2198 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2199 !! (caps & CTDB_CAP_LMASTER), options.sep);
2201 printf("RECMASTER: %s\n",
2202 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2203 printf("LMASTER: %s\n",
2204 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2210 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2211 int argc, const char **argv)
2213 printf("%u\n", ctdb_client_pnn(ctdb->client));
2217 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2218 int argc, const char **argv)
2220 char *t, *lvs_helper = NULL;
2226 t = getenv("CTDB_LVS_HELPER");
2228 lvs_helper = talloc_strdup(mem_ctx, t);
2230 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2231 CTDB_HELPER_BINDIR);
2234 if (lvs_helper == NULL) {
2235 fprintf(stderr, "Unable to set LVS helper\n");
2239 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2242 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2243 int argc, const char **argv)
2253 found = debug_level_parse(argv[0], &log_level);
2256 "Invalid debug level '%s'. Valid levels are:\n",
2258 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2262 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2263 ctdb->cmd_pnn, TIMEOUT(), log_level);
2271 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2272 int argc, const char **argv)
2275 const char *log_str;
2282 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2283 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2288 log_str = debug_level_to_string(loglevel);
2289 printf("%s\n", log_str);
2294 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2295 int argc, const char **argv)
2297 const char *db_name;
2298 uint8_t db_flags = 0;
2301 if (argc < 1 || argc > 2) {
2307 if (strcmp(argv[1], "persistent") == 0) {
2308 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2309 } else if (strcmp(argv[1], "readonly") == 0) {
2310 db_flags = CTDB_DB_FLAGS_READONLY;
2311 } else if (strcmp(argv[1], "sticky") == 0) {
2312 db_flags = CTDB_DB_FLAGS_STICKY;
2313 } else if (strcmp(argv[1], "replicated") == 0) {
2314 db_flags = CTDB_DB_FLAGS_REPLICATED;
2320 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2329 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2330 int argc, const char **argv)
2332 const char *db_name;
2335 struct ctdb_node_map *nodemap;
2343 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2344 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2349 if (recmode == CTDB_RECOVERY_ACTIVE) {
2350 fprintf(stderr, "Database cannot be detached"
2351 " when recovery is active\n");
2355 nodemap = get_nodemap(ctdb, false);
2356 if (nodemap == NULL) {
2360 for (i=0; i<nodemap->num; i++) {
2363 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2366 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2369 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2370 fprintf(stderr, "Database cannot be detached on"
2371 " inactive (stopped or banned) node %u\n",
2372 nodemap->node[i].pnn);
2376 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2377 nodemap->node[i].pnn, TIMEOUT(),
2378 "AllowClientDBAttach", &value);
2381 "Unable to get tunable AllowClientDBAttach"
2382 " from node %u\n", nodemap->node[i].pnn);
2388 "Database access is still active on node %u."
2389 " Set AllowclientDBAttach=0 on all nodes.\n",
2390 nodemap->node[i].pnn);
2396 for (i=0; i<argc; i++) {
2397 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2403 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2405 "Only volatile databases can be detached\n");
2409 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2411 fprintf(stderr, "Database %s detach failed\n", db_name);
2419 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2420 int argc, const char **argv)
2422 const char *mem_str;
2426 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2427 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2432 n = write(1, mem_str, strlen(mem_str)+1);
2433 if (n < 0 || n != strlen(mem_str)+1) {
2434 fprintf(stderr, "Failed to write talloc summary\n");
2441 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2443 bool *done = (bool *)private_data;
2446 n = write(1, data.dptr, data.dsize);
2447 if (n < 0 || n != data.dsize) {
2448 fprintf(stderr, "Failed to write talloc summary\n");
2454 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2455 int argc, const char **argv)
2457 struct ctdb_srvid_message msg = { 0 };
2461 msg.pnn = ctdb->pnn;
2462 msg.srvid = next_srvid(ctdb);
2464 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2465 msg.srvid, dump_memory, &done);
2470 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2471 ctdb->cmd_pnn, &msg);
2476 ctdb_client_wait(ctdb->ev, &done);
2480 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2481 int argc, const char **argv)
2486 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2487 ctdb->cmd_pnn, TIMEOUT(), &pid);
2492 printf("%u\n", pid);
2496 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2497 const char *desc, uint32_t flag, bool set_flag)
2499 struct ctdb_node_map *nodemap;
2502 nodemap = get_nodemap(ctdb, false);
2503 if (nodemap == NULL) {
2507 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2508 if (set_flag == flag_is_set) {
2510 fprintf(stderr, "Node %u is already %s\n",
2511 ctdb->cmd_pnn, desc);
2513 fprintf(stderr, "Node %u is not %s\n",
2514 ctdb->cmd_pnn, desc);
2522 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2523 uint32_t flag, bool set_flag)
2525 struct ctdb_node_map *nodemap;
2529 nodemap = get_nodemap(ctdb, true);
2530 if (nodemap == NULL) {
2532 "Failed to get nodemap, trying again\n");
2537 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2538 if (flag_is_set == set_flag) {
2546 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2547 struct ctdb_client_context *client,
2548 uint32_t destnode, struct timeval timeout,
2549 uint32_t set, uint32_t clear)
2551 struct ctdb_node_map *nodemap;
2552 struct ctdb_node_flag_change flag_change;
2553 struct ctdb_req_control request;
2557 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2558 tevent_timeval_zero(), &nodemap);
2563 flag_change.pnn = destnode;
2564 flag_change.old_flags = nodemap->node[destnode].flags;
2565 flag_change.new_flags = flag_change.old_flags | set;
2566 flag_change.new_flags &= ~clear;
2568 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2573 ctdb_req_control_modify_flags(&request, &flag_change);
2574 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2575 tevent_timeval_zero(), &request,
2580 struct ipreallocate_state {
2585 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2588 struct ipreallocate_state *state =
2589 (struct ipreallocate_state *)private_data;
2591 if (data.dsize != sizeof(int)) {
2596 state->status = *(int *)data.dptr;
2600 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2602 struct ctdb_srvid_message msg = { 0 };
2603 struct ipreallocate_state state;
2606 msg.pnn = ctdb->pnn;
2607 msg.srvid = next_srvid(ctdb);
2610 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2612 ipreallocate_handler, &state);
2618 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2620 CTDB_BROADCAST_CONNECTED,
2626 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2632 if (state.status >= 0) {
2641 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2646 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2647 int argc, const char **argv)
2655 ret = check_flags(mem_ctx, ctdb, "disabled",
2656 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2661 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2662 ctdb->cmd_pnn, TIMEOUT(),
2663 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2666 "Failed to set DISABLED flag on node %u\n",
2671 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2672 return ipreallocate(mem_ctx, ctdb);
2675 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2676 int argc, const char **argv)
2684 ret = check_flags(mem_ctx, ctdb, "disabled",
2685 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2690 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2691 ctdb->cmd_pnn, TIMEOUT(),
2692 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2694 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2699 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2700 return ipreallocate(mem_ctx, ctdb);
2703 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2704 int argc, const char **argv)
2712 ret = check_flags(mem_ctx, ctdb, "stopped",
2713 NODE_FLAGS_STOPPED, true);
2718 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2719 ctdb->cmd_pnn, TIMEOUT());
2721 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2725 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2726 return ipreallocate(mem_ctx, ctdb);
2729 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2730 int argc, const char **argv)
2738 ret = check_flags(mem_ctx, ctdb, "stopped",
2739 NODE_FLAGS_STOPPED, false);
2744 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2745 ctdb->cmd_pnn, TIMEOUT());
2747 fprintf(stderr, "Failed to continue stopped node %u\n",
2752 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2753 return ipreallocate(mem_ctx, ctdb);
2756 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2757 int argc, const char **argv)
2759 struct ctdb_ban_state ban_state;
2766 ret = check_flags(mem_ctx, ctdb, "banned",
2767 NODE_FLAGS_BANNED, true);
2772 ban_state.pnn = ctdb->cmd_pnn;
2773 ban_state.time = strtoul(argv[0], NULL, 0);
2775 if (ban_state.time == 0) {
2776 fprintf(stderr, "Ban time cannot be zero\n");
2780 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2781 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2783 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2787 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2788 return ipreallocate(mem_ctx, ctdb);
2792 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2793 int argc, const char **argv)
2795 struct ctdb_ban_state ban_state;
2802 ret = check_flags(mem_ctx, ctdb, "banned",
2803 NODE_FLAGS_BANNED, false);
2808 ban_state.pnn = ctdb->cmd_pnn;
2811 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2812 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2814 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2818 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2819 return ipreallocate(mem_ctx, ctdb);
2823 static void wait_for_shutdown(void *private_data)
2825 bool *done = (bool *)private_data;
2830 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2831 int argc, const char **argv)
2840 if (ctdb->pnn == ctdb->cmd_pnn) {
2841 ctdb_client_set_disconnect_callback(ctdb->client,
2846 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2847 ctdb->cmd_pnn, TIMEOUT());
2849 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2853 if (ctdb->pnn == ctdb->cmd_pnn) {
2854 ctdb_client_wait(ctdb->ev, &done);
2860 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2861 uint32_t *generation)
2865 struct ctdb_vnn_map *vnnmap;
2869 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2870 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2872 fprintf(stderr, "Failed to find recovery master\n");
2876 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2877 recmaster, TIMEOUT(), &recmode);
2879 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2884 if (recmode == CTDB_RECOVERY_ACTIVE) {
2889 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2890 recmaster, TIMEOUT(), &vnnmap);
2892 fprintf(stderr, "Failed to get generation from node %u\n",
2897 if (vnnmap->generation == INVALID_GENERATION) {
2898 talloc_free(vnnmap);
2903 *generation = vnnmap->generation;
2904 talloc_free(vnnmap);
2909 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2910 int argc, const char **argv)
2912 uint32_t generation, next_generation;
2919 ret = get_generation(mem_ctx, ctdb, &generation);
2924 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2925 ctdb->cmd_pnn, TIMEOUT(),
2926 CTDB_RECOVERY_ACTIVE);
2928 fprintf(stderr, "Failed to set recovery mode active\n");
2933 ret = get_generation(mem_ctx, ctdb, &next_generation);
2936 "Failed to confirm end of recovery\n");
2940 if (next_generation != generation) {
2950 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2951 int argc, const char **argv)
2954 usage("ipreallocate");
2957 return ipreallocate(mem_ctx, ctdb);
2960 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2961 struct ctdb_context *ctdb,
2962 int argc, const char **argv)
2968 usage("isnotrecmaster");
2971 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2972 ctdb->pnn, TIMEOUT(), &recmaster);
2974 fprintf(stderr, "Failed to get recmaster\n");
2978 if (recmaster != ctdb->pnn) {
2979 printf("this node is not the recmaster\n");
2983 printf("this node is the recmaster\n");
2987 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2988 int argc, const char **argv)
2990 struct ctdb_addr_info addr_info;
2997 ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
2999 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3002 addr_info.iface = argv[1];
3004 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3005 ctdb->cmd_pnn, TIMEOUT(),
3008 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3016 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3017 int argc, const char **argv)
3019 ctdb_sock_addr src, dst;
3022 if (argc != 0 && argc != 2) {
3027 struct ctdb_connection_list *clist;
3029 unsigned int num_failed;
3031 /* Client first but the src/dst logic is confused */
3032 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3038 for (i = 0; i < clist->num; i++) {
3039 ret = ctdb_sys_send_tcp(&clist->conn[i].src,
3040 &clist->conn[i].dst,
3049 if (num_failed > 0) {
3050 fprintf(stderr, "Failed to send %d tickles\n",
3059 ret = ctdb_sock_addr_from_string(argv[0], &src, true);
3061 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3065 ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
3067 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3071 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3073 fprintf(stderr, "Failed to send tickle ack\n");
3080 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3081 int argc, const char **argv)
3083 ctdb_sock_addr addr;
3084 struct ctdb_tickle_list *tickles;
3088 if (argc < 1 || argc > 2) {
3089 usage("gettickles");
3093 port = strtoul(argv[1], NULL, 10);
3096 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3098 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3101 ctdb_sock_addr_set_port(&addr, port);
3103 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3104 ctdb->cmd_pnn, TIMEOUT(), &addr,
3107 fprintf(stderr, "Failed to get list of connections\n");
3111 if (options.machinereadable) {
3112 printf("%s%s%s%s%s%s%s%s%s\n",
3114 "Source IP", options.sep,
3115 "Port", options.sep,
3116 "Destiation IP", options.sep,
3117 "Port", options.sep);
3118 for (i=0; i<tickles->num; i++) {
3119 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3120 ctdb_sock_addr_to_string(
3121 mem_ctx, &tickles->conn[i].src, false),
3123 ntohs(tickles->conn[i].src.ip.sin_port),
3125 ctdb_sock_addr_to_string(
3126 mem_ctx, &tickles->conn[i].dst, false),
3128 ntohs(tickles->conn[i].dst.ip.sin_port),
3132 printf("Connections for IP: %s\n",
3133 ctdb_sock_addr_to_string(mem_ctx,
3134 &tickles->addr, false));
3135 printf("Num connections: %u\n", tickles->num);
3136 for (i=0; i<tickles->num; i++) {
3137 printf("SRC: %s DST: %s\n",
3138 ctdb_sock_addr_to_string(
3139 mem_ctx, &tickles->conn[i].src, true),
3140 ctdb_sock_addr_to_string(
3141 mem_ctx, &tickles->conn[i].dst, true));
3145 talloc_free(tickles);
3149 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3150 struct ctdb_connection *conn);
3152 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3154 struct process_clist_state {
3155 struct ctdb_connection_list *clist;
3157 int num_failed, num_total;
3158 clist_reply_func reply_func;
3161 static void process_clist_done(struct tevent_req *subreq);
3163 static struct tevent_req *process_clist_send(
3164 TALLOC_CTX *mem_ctx,
3165 struct ctdb_context *ctdb,
3166 struct ctdb_connection_list *clist,
3167 clist_request_func request_func,
3168 clist_reply_func reply_func)
3170 struct tevent_req *req, *subreq;
3171 struct process_clist_state *state;
3172 struct ctdb_req_control request;
3175 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3180 state->clist = clist;
3181 state->reply_func = reply_func;
3183 for (i = 0; i < clist->num; i++) {
3184 request_func(&request, &clist->conn[i]);
3185 subreq = ctdb_client_control_send(state, ctdb->ev,
3186 ctdb->client, ctdb->cmd_pnn,
3187 TIMEOUT(), &request);
3188 if (tevent_req_nomem(subreq, req)) {
3189 return tevent_req_post(req, ctdb->ev);
3191 tevent_req_set_callback(subreq, process_clist_done, req);
3197 static void process_clist_done(struct tevent_req *subreq)
3199 struct tevent_req *req = tevent_req_callback_data(
3200 subreq, struct tevent_req);
3201 struct process_clist_state *state = tevent_req_data(
3202 req, struct process_clist_state);
3203 struct ctdb_reply_control *reply;
3207 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3208 TALLOC_FREE(subreq);
3210 state->num_failed += 1;
3214 ret = state->reply_func(reply);
3216 state->num_failed += 1;
3221 state->num_total += 1;
3222 if (state->num_total == state->clist->num) {
3223 tevent_req_done(req);
3227 static int process_clist_recv(struct tevent_req *req)
3229 struct process_clist_state *state = tevent_req_data(
3230 req, struct process_clist_state);
3232 return state->num_failed;
3235 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3236 int argc, const char **argv)
3238 struct ctdb_connection conn;
3241 if (argc != 0 && argc != 2) {
3246 struct ctdb_connection_list *clist;
3247 struct tevent_req *req;
3249 /* Client first but the src/dst logic is confused */
3250 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3254 if (clist->num == 0) {
3258 req = process_clist_send(mem_ctx, ctdb, clist,
3259 ctdb_req_control_tcp_add_delayed_update,
3260 ctdb_reply_control_tcp_add_delayed_update);
3266 tevent_req_poll(req, ctdb->ev);
3269 ret = process_clist_recv(req);
3271 fprintf(stderr, "Failed to add %d tickles\n", ret);
3278 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3280 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3283 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3285 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3289 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3290 ctdb->client, ctdb->cmd_pnn,
3293 fprintf(stderr, "Failed to register connection\n");
3300 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3301 int argc, const char **argv)
3303 struct ctdb_connection conn;
3306 if (argc != 0 && argc != 2) {
3311 struct ctdb_connection_list *clist;
3312 struct tevent_req *req;
3314 /* Client first but the src/dst logic is confused */
3315 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3319 if (clist->num == 0) {
3323 req = process_clist_send(mem_ctx, ctdb, clist,
3324 ctdb_req_control_tcp_remove,
3325 ctdb_reply_control_tcp_remove);
3331 tevent_req_poll(req, ctdb->ev);
3334 ret = process_clist_recv(req);
3336 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3343 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3345 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3348 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3350 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3354 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3355 ctdb->cmd_pnn, TIMEOUT(), &conn);
3357 fprintf(stderr, "Failed to unregister connection\n");
3364 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3365 int argc, const char **argv)
3367 struct ctdb_node_map *nodemap;
3374 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3375 if (nodemap == NULL) {
3379 for (i=0; i<nodemap->num; i++) {
3380 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3384 if (options.machinereadable) {
3385 printf("%s%u%s%s%s\n", options.sep,
3386 nodemap->node[i].pnn, options.sep,
3387 ctdb_sock_addr_to_string(
3388 mem_ctx, &nodemap->node[i].addr, false),
3392 ctdb_sock_addr_to_string(
3393 mem_ctx, &nodemap->node[i].addr, false));
3400 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3401 struct ctdb_node_map *nodemap2)
3405 if (nodemap1->num != nodemap2->num) {
3409 for (i=0; i<nodemap1->num; i++) {
3410 struct ctdb_node_and_flags *n1, *n2;
3412 n1 = &nodemap1->node[i];
3413 n2 = &nodemap2->node[i];
3415 if ((n1->pnn != n2->pnn) ||
3416 (n1->flags != n2->flags) ||
3417 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3425 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3426 struct ctdb_node_map *nm,
3427 struct ctdb_node_map *fnm,
3431 bool check_failed = false;
3435 for (i=0; i<nm->num; i++) {
3436 if (i >= fnm->num) {
3438 "Node %u (%s) missing from nodes file\n",
3440 ctdb_sock_addr_to_string(
3441 mem_ctx, &nm->node[i].addr, false));
3442 check_failed = true;
3445 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3446 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3447 /* Node remains deleted */
3451 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3452 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3453 /* Node not newly nor previously deleted */
3454 if (! ctdb_same_ip(&nm->node[i].addr,
3455 &fnm->node[i].addr)) {
3457 "Node %u has changed IP address"
3458 " (was %s, now %s)\n",
3460 ctdb_sock_addr_to_string(
3462 &nm->node[i].addr, false),
3463 ctdb_sock_addr_to_string(
3465 &fnm->node[i].addr, false));
3466 check_failed = true;
3468 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3470 "WARNING: Node %u is disconnected."
3471 " You MUST fix this node manually!\n",
3478 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3479 /* Node is being deleted */
3480 printf("Node %u is DELETED\n", nm->node[i].pnn);
3482 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3484 "ERROR: Node %u is still connected\n",
3486 check_failed = true;
3491 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3492 /* Node was previously deleted */
3493 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3500 "ERROR: Nodes will not be reloaded due to previous error\n");
3504 /* Leftover nodes in file are NEW */
3505 for (; i < fnm->num; i++) {
3506 printf("Node %u is NEW\n", fnm->node[i].pnn);
3513 struct disable_recoveries_state {
3521 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3524 struct disable_recoveries_state *state =
3525 (struct disable_recoveries_state *)private_data;
3528 if (data.dsize != sizeof(int)) {
3533 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3534 ret = *(int *)data.dptr;
3536 state->status = ret;
3540 for (i=0; i<state->node_count; i++) {
3541 if (state->pnn_list[i] == ret) {
3542 state->reply[i] = true;
3548 for (i=0; i<state->node_count; i++) {
3549 if (! state->reply[i]) {
3550 state->done = false;
3556 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3557 uint32_t timeout, uint32_t *pnn_list, int count)
3559 struct ctdb_disable_message disable = { 0 };
3560 struct disable_recoveries_state state;
3563 disable.pnn = ctdb->pnn;
3564 disable.srvid = next_srvid(ctdb);
3565 disable.timeout = timeout;
3567 state.pnn_list = pnn_list;
3568 state.node_count = count;
3571 state.reply = talloc_zero_array(mem_ctx, bool, count);
3572 if (state.reply == NULL) {
3576 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3578 disable_recoveries_handler,
3584 for (i=0; i<count; i++) {
3585 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3594 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3596 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3598 ret = (state.status >= 0 ? 0 : 1);
3602 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3603 disable.srvid, &state);
3607 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3608 int argc, const char **argv)
3610 struct ctdb_node_map *nodemap = NULL;
3611 struct ctdb_node_map *file_nodemap;
3612 struct ctdb_node_map *remote_nodemap;
3613 struct ctdb_req_control request;
3614 struct ctdb_reply_control **reply;
3620 nodemap = get_nodemap(ctdb, false);
3621 if (nodemap == NULL) {
3625 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3626 if (file_nodemap == NULL) {
3630 for (i=0; i<nodemap->num; i++) {
3631 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3635 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3636 nodemap->node[i].pnn, TIMEOUT(),
3640 "ERROR: Failed to get nodes file from node %u\n",
3641 nodemap->node[i].pnn);
3645 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3647 "ERROR: Nodes file on node %u differs"
3648 " from current node (%u)\n",
3649 nodemap->node[i].pnn, ctdb->pnn);
3654 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3660 fprintf(stderr, "No change in nodes file,"
3661 " skipping unnecessary reload\n");
3665 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3666 mem_ctx, &pnn_list);
3668 fprintf(stderr, "Memory allocation error\n");
3672 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3675 fprintf(stderr, "Failed to disable recoveries\n");
3679 ctdb_req_control_reload_nodes_file(&request);
3680 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3681 pnn_list, count, TIMEOUT(),
3682 &request, NULL, &reply);
3684 bool failed = false;
3686 for (i=0; i<count; i++) {
3687 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3690 "Node %u failed to reload nodes\n",
3697 "You MUST fix failed nodes manually!\n");
3701 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3703 fprintf(stderr, "Failed to enable recoveries\n");
3710 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3711 ctdb_sock_addr *addr, uint32_t pnn)
3713 struct ctdb_public_ip_list *pubip_list;
3714 struct ctdb_public_ip pubip;
3715 struct ctdb_node_map *nodemap;
3716 struct ctdb_req_control request;
3720 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3721 CTDB_BROADCAST_CONNECTED,
3722 2*options.timelimit);
3724 fprintf(stderr, "Failed to disable IP check\n");
3728 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3729 pnn, TIMEOUT(), false, &pubip_list);
3731 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3736 for (i=0; i<pubip_list->num; i++) {
3737 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3742 if (i == pubip_list->num) {
3743 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3744 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3748 nodemap = get_nodemap(ctdb, false);
3749 if (nodemap == NULL) {
3753 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3755 fprintf(stderr, "Memory allocation error\n");
3761 ctdb_req_control_release_ip(&request, &pubip);
3763 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3764 pnn_list, count, TIMEOUT(),
3765 &request, NULL, NULL);
3767 fprintf(stderr, "Failed to release IP on nodes\n");
3771 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3772 pnn, TIMEOUT(), &pubip);
3774 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3781 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3782 int argc, const char **argv)
3784 ctdb_sock_addr addr;
3786 int ret, retries = 0;
3792 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3794 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3798 pnn = strtoul(argv[1], NULL, 10);
3799 if (pnn == CTDB_UNKNOWN_PNN) {
3800 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3804 while (retries < 5) {
3805 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3815 fprintf(stderr, "Failed to move IP %s to node %u\n",
3823 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3828 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3829 CTDB_BROADCAST_CONNECTED, pnn);
3832 "Failed to ask recovery master to distribute IPs\n");
3839 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3840 int argc, const char **argv)
3842 ctdb_sock_addr addr;
3843 struct ctdb_public_ip_list *pubip_list;
3844 struct ctdb_addr_info addr_info;
3846 int ret, i, retries = 0;
3852 ret = ctdb_sock_addr_mask_from_string(argv[0], &addr, &mask);
3854 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3858 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3859 ctdb->cmd_pnn, TIMEOUT(),
3860 false, &pubip_list);
3862 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3867 for (i=0; i<pubip_list->num; i++) {
3868 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3869 fprintf(stderr, "Node already knows about IP %s\n",
3870 ctdb_sock_addr_to_string(mem_ctx,
3876 addr_info.addr = addr;
3877 addr_info.mask = mask;
3878 addr_info.iface = argv[1];
3880 while (retries < 5) {
3881 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3882 ctdb->cmd_pnn, TIMEOUT(),
3893 fprintf(stderr, "Failed to add public IP to node %u."
3894 " Giving up\n", ctdb->cmd_pnn);
3898 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3906 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3907 int argc, const char **argv)
3909 ctdb_sock_addr addr;
3910 struct ctdb_public_ip_list *pubip_list;
3911 struct ctdb_addr_info addr_info;
3918 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3920 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3924 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3925 ctdb->cmd_pnn, TIMEOUT(),
3926 false, &pubip_list);
3928 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3933 for (i=0; i<pubip_list->num; i++) {
3934 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3939 if (i == pubip_list->num) {
3940 fprintf(stderr, "Node does not know about IP address %s\n",
3941 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
3945 addr_info.addr = addr;
3947 addr_info.iface = NULL;
3949 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3950 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3952 fprintf(stderr, "Failed to delete public IP from node %u\n",
3960 #define DB_VERSION 3
3961 #define MAX_DB_NAME 64
3962 #define MAX_REC_BUFFER_SIZE (100*1000)
3965 unsigned long version;
3967 unsigned long flags;
3970 char name[MAX_DB_NAME];
3973 struct backup_state {
3974 TALLOC_CTX *mem_ctx;
3975 struct ctdb_rec_buffer *recbuf;
3978 unsigned int nbuf, nrec;
3981 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
3982 TDB_DATA key, TDB_DATA data, void *private_data)
3984 struct backup_state *state = (struct backup_state *)private_data;
3988 if (state->recbuf == NULL) {
3989 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
3991 if (state->recbuf == NULL) {
3996 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4002 len = ctdb_rec_buffer_len(state->recbuf);
4003 if (len < MAX_REC_BUFFER_SIZE) {
4007 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4009 fprintf(stderr, "Failed to write records to backup file\n");
4014 state->nrec += state->recbuf->count;
4015 TALLOC_FREE(state->recbuf);
4020 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4021 int argc, const char **argv)
4023 const char *db_name;
4024 struct ctdb_db_context *db;
4027 struct backup_state state;
4028 struct db_header db_hdr;
4035 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4039 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4042 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4046 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4049 fprintf(stderr, "Failed to open file %s for writing\n",
4054 /* Write empty header first */
4055 ZERO_STRUCT(db_hdr);
4056 ret = write(fd, &db_hdr, sizeof(struct db_header));
4060 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4064 state.mem_ctx = mem_ctx;
4065 state.recbuf = NULL;
4070 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4072 fprintf(stderr, "Failed to collect records from DB %s\n",
4078 if (state.recbuf != NULL) {
4079 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4082 "Failed to write records to backup file\n");
4088 state.nrec += state.recbuf->count;
4089 TALLOC_FREE(state.recbuf);
4092 db_hdr.version = DB_VERSION;
4093 db_hdr.timestamp = time(NULL);
4094 db_hdr.flags = db_flags;
4095 db_hdr.nbuf = state.nbuf;
4096 db_hdr.nrec = state.nrec;
4097 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4099 lseek(fd, 0, SEEK_SET);
4100 ret = write(fd, &db_hdr, sizeof(struct db_header));
4104 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4109 printf("Database backed up to %s\n", argv[1]);
4113 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4114 int argc, const char **argv)
4116 const char *db_name = NULL;
4117 struct ctdb_db_context *db;
4118 struct db_header db_hdr;
4119 struct ctdb_node_map *nodemap;
4120 struct ctdb_req_control request;
4121 struct ctdb_reply_control **reply;
4122 struct ctdb_transdb wipedb;
4123 struct ctdb_pulldb_ext pulldb;
4124 struct ctdb_rec_buffer *recbuf;
4125 uint32_t generation;
4133 if (argc < 1 || argc > 2) {
4137 fd = open(argv[0], O_RDONLY, 0600);
4140 fprintf(stderr, "Failed to open file %s for reading\n",
4149 n = read(fd, &db_hdr, sizeof(struct db_header));
4153 fprintf(stderr, "Failed to read db header from file %s\n",
4157 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4159 if (db_hdr.version != DB_VERSION) {
4161 "Wrong version of backup file, expected %u, got %lu\n",
4162 DB_VERSION, db_hdr.version);
4167 if (db_name == NULL) {
4168 db_name = db_hdr.name;
4171 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4172 localtime(&db_hdr.timestamp));
4173 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4175 db_flags = db_hdr.flags & 0xff;
4176 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4179 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4184 nodemap = get_nodemap(ctdb, false);
4185 if (nodemap == NULL) {
4186 fprintf(stderr, "Failed to get nodemap\n");
4191 ret = get_generation(mem_ctx, ctdb, &generation);
4193 fprintf(stderr, "Failed to get current generation\n");
4198 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4205 wipedb.db_id = ctdb_db_id(db);
4206 wipedb.tid = generation;
4208 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4209 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4210 ctdb->client, pnn_list, count,
4211 TIMEOUT(), &request, NULL, NULL);
4217 ctdb_req_control_db_transaction_start(&request, &wipedb);
4218 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4219 pnn_list, count, TIMEOUT(),
4220 &request, NULL, NULL);
4225 ctdb_req_control_wipe_database(&request, &wipedb);
4226 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4227 pnn_list, count, TIMEOUT(),
4228 &request, NULL, NULL);
4233 pulldb.db_id = ctdb_db_id(db);
4235 pulldb.srvid = SRVID_CTDB_PUSHDB;
4237 ctdb_req_control_db_push_start(&request, &pulldb);
4238 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4239 pnn_list, count, TIMEOUT(),
4240 &request, NULL, NULL);
4245 for (i=0; i<db_hdr.nbuf; i++) {
4246 struct ctdb_req_message message;
4250 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4255 data.dsize = ctdb_rec_buffer_len(recbuf);
4256 data.dptr = talloc_size(mem_ctx, data.dsize);
4257 if (data.dptr == NULL) {
4261 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4263 message.srvid = pulldb.srvid;
4264 message.data.data = data;
4266 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4274 talloc_free(recbuf);
4275 talloc_free(data.dptr);
4278 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4279 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4280 pnn_list, count, TIMEOUT(),
4281 &request, NULL, &reply);
4286 for (i=0; i<count; i++) {
4287 uint32_t num_records;
4289 ret = ctdb_reply_control_db_push_confirm(reply[i],
4292 fprintf(stderr, "Invalid response from node %u\n",
4297 if (num_records != db_hdr.nrec) {
4298 fprintf(stderr, "Node %u received %u of %lu records\n",
4299 pnn_list[i], num_records, db_hdr.nrec);
4304 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4305 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4306 pnn_list, count, TIMEOUT(),
4307 &request, NULL, NULL);
4312 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4313 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4314 pnn_list, count, TIMEOUT(),
4315 &request, NULL, NULL);
4320 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4321 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4322 ctdb->client, pnn_list, count,
4323 TIMEOUT(), &request, NULL, NULL);
4328 printf("Database %s restored\n", db_name);
4335 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4336 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4340 struct dumpdbbackup_state {
4341 ctdb_rec_parser_func_t parser;
4342 struct dump_record_state sub_state;
4345 static int dumpdbbackup_handler(uint32_t reqid,
4346 struct ctdb_ltdb_header *header,
4347 TDB_DATA key, TDB_DATA data,
4350 struct dumpdbbackup_state *state =
4351 (struct dumpdbbackup_state *)private_data;
4352 struct ctdb_ltdb_header hdr;
4355 ret = ctdb_ltdb_header_extract(&data, &hdr);
4360 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4363 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4364 int argc, const char **argv)
4366 struct db_header db_hdr;
4368 struct dumpdbbackup_state state;
4373 usage("dumpbackup");
4376 fd = open(argv[0], O_RDONLY, 0600);
4379 fprintf(stderr, "Failed to open file %s for reading\n",
4384 n = read(fd, &db_hdr, sizeof(struct db_header));
4388 fprintf(stderr, "Failed to read db header from file %s\n",
4392 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4394 if (db_hdr.version != DB_VERSION) {
4396 "Wrong version of backup file, expected %u, got %lu\n",
4397 DB_VERSION, db_hdr.version);
4402 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4403 localtime(&db_hdr.timestamp));
4404 printf("Dumping database %s from backup @ %s\n",
4405 db_hdr.name, timebuf);
4407 state.parser = dump_record;
4408 state.sub_state.count = 0;
4410 for (i=0; i<db_hdr.nbuf; i++) {
4411 struct ctdb_rec_buffer *recbuf;
4413 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4415 fprintf(stderr, "Failed to read records\n");
4420 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4423 fprintf(stderr, "Failed to dump records\n");
4430 printf("Dumped %u record(s)\n", state.sub_state.count);
4434 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4435 int argc, const char **argv)
4437 const char *db_name;
4438 struct ctdb_db_context *db;
4441 struct ctdb_node_map *nodemap;
4442 struct ctdb_req_control request;
4443 struct ctdb_transdb wipedb;
4444 uint32_t generation;
4452 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4456 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4459 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4463 nodemap = get_nodemap(ctdb, false);
4464 if (nodemap == NULL) {
4465 fprintf(stderr, "Failed to get nodemap\n");
4469 ret = get_generation(mem_ctx, ctdb, &generation);
4471 fprintf(stderr, "Failed to get current generation\n");
4475 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4481 ctdb_req_control_db_freeze(&request, db_id);
4482 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4483 ctdb->client, pnn_list, count,
4484 TIMEOUT(), &request, NULL, NULL);
4489 wipedb.db_id = db_id;
4490 wipedb.tid = generation;
4492 ctdb_req_control_db_transaction_start(&request, &wipedb);
4493 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4494 pnn_list, count, TIMEOUT(),
4495 &request, NULL, NULL);
4500 ctdb_req_control_wipe_database(&request, &wipedb);
4501 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4502 pnn_list, count, TIMEOUT(),
4503 &request, NULL, NULL);
4508 ctdb_req_control_db_set_healthy(&request, db_id);
4509 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4510 pnn_list, count, TIMEOUT(),
4511 &request, NULL, NULL);
4516 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4517 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4518 pnn_list, count, TIMEOUT(),
4519 &request, NULL, NULL);
4524 ctdb_req_control_db_thaw(&request, db_id);
4525 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4526 ctdb->client, pnn_list, count,
4527 TIMEOUT(), &request, NULL, NULL);
4532 printf("Database %s wiped\n", db_name);
4537 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4538 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4542 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4543 int argc, const char **argv)
4548 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4549 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4554 printf("%u\n", recmaster);
4558 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4559 int argc, const char **argv)
4561 char *t, *event_helper = NULL;
4563 t = getenv("CTDB_EVENT_HELPER");
4565 event_helper = talloc_strdup(mem_ctx, t);
4567 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb-event",
4568 CTDB_HELPER_BINDIR);
4571 if (event_helper == NULL) {
4572 fprintf(stderr, "Unable to set event daemon helper\n");
4576 return run_helper(mem_ctx, "event daemon helper", event_helper,
4580 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4581 int argc, const char **argv)
4583 const char *new_argv[4];
4586 usage("scriptstatus");
4589 new_argv[0] = "status";
4590 new_argv[1] = "legacy";
4591 new_argv[2] = (argc == 0) ? "monitor" : argv[0];
4594 (void) control_event(mem_ctx, ctdb, 3, new_argv);
4598 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4599 int argc, const char **argv)
4601 char *t, *natgw_helper = NULL;
4607 t = getenv("CTDB_NATGW_HELPER");
4609 natgw_helper = talloc_strdup(mem_ctx, t);
4611 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4612 CTDB_HELPER_BINDIR);
4615 if (natgw_helper == NULL) {
4616 fprintf(stderr, "Unable to set NAT gateway helper\n");
4620 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4625 * Find the PNN of the current node
4626 * discover the pnn by loading the nodes file and try to bind
4627 * to all addresses one at a time until the ip address is found.
4629 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4631 struct ctdb_node_map *nodemap;
4634 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4635 if (nodemap == NULL) {
4639 for (i=0; i<nodemap->num; i++) {
4640 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4643 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4645 *pnn = nodemap->node[i].pnn;
4647 talloc_free(nodemap);
4652 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4653 talloc_free(nodemap);
4657 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4658 int argc, const char **argv)
4660 const char *reclock;
4664 usage("getreclock");
4667 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4668 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4673 if (reclock != NULL) {
4674 printf("%s\n", reclock);
4680 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4681 struct ctdb_context *ctdb,
4682 int argc, const char **argv)
4684 uint32_t lmasterrole = 0;
4688 usage("setlmasterrole");
4691 if (strcmp(argv[0], "on") == 0) {
4693 } else if (strcmp(argv[0], "off") == 0) {
4696 usage("setlmasterrole");
4699 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4700 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4708 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4709 struct ctdb_context *ctdb,
4710 int argc, const char **argv)
4712 uint32_t recmasterrole = 0;
4716 usage("setrecmasterrole");
4719 if (strcmp(argv[0], "on") == 0) {
4721 } else if (strcmp(argv[0], "off") == 0) {
4724 usage("setrecmasterrole");
4727 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4728 ctdb->cmd_pnn, TIMEOUT(),
4737 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4738 struct ctdb_context *ctdb,
4739 int argc, const char **argv)
4746 usage("setdbreadonly");
4749 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4753 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4754 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4758 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4759 ctdb->cmd_pnn, TIMEOUT(), db_id);
4767 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4768 int argc, const char **argv)
4775 usage("setdbsticky");
4778 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4782 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4783 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4787 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4788 ctdb->cmd_pnn, TIMEOUT(), db_id);
4796 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4797 int argc, const char **argv)
4799 const char *db_name;
4800 struct ctdb_db_context *db;
4801 struct ctdb_transaction_handle *h;
4806 if (argc < 2 || argc > 3) {
4810 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4815 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4816 fprintf(stderr, "Transactions not supported on DB %s\n",
4821 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4824 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4828 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4830 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4834 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4835 TIMEOUT(), db, true, &h);
4837 fprintf(stderr, "Failed to start transaction on db %s\n",
4842 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4844 fprintf(stderr, "Failed to read record for key %s\n",
4846 ctdb_transaction_cancel(h);
4850 printf("%.*s\n", (int)data.dsize, data.dptr);
4852 ctdb_transaction_cancel(h);
4856 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4857 int argc, const char **argv)
4859 const char *db_name;
4860 struct ctdb_db_context *db;
4861 struct ctdb_transaction_handle *h;
4870 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4875 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4876 fprintf(stderr, "Transactions not supported on DB %s\n",
4881 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4884 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4888 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4890 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4894 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4896 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4900 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4901 TIMEOUT(), db, false, &h);
4903 fprintf(stderr, "Failed to start transaction on db %s\n",
4908 ret = ctdb_transaction_store_record(h, key, data);
4910 fprintf(stderr, "Failed to store record for key %s\n",
4912 ctdb_transaction_cancel(h);
4916 ret = ctdb_transaction_commit(h);
4918 fprintf(stderr, "Failed to commit transaction on db %s\n",
4920 ctdb_transaction_cancel(h);
4927 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4928 int argc, const char **argv)
4930 const char *db_name;
4931 struct ctdb_db_context *db;
4932 struct ctdb_transaction_handle *h;
4941 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4946 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4947 fprintf(stderr, "Transactions not supported on DB %s\n",
4952 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4955 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4959 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4961 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4965 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4966 TIMEOUT(), db, false, &h);
4968 fprintf(stderr, "Failed to start transaction on db %s\n",
4973 ret = ctdb_transaction_delete_record(h, key);
4975 fprintf(stderr, "Failed to delete record for key %s\n",
4977 ctdb_transaction_cancel(h);
4981 ret = ctdb_transaction_commit(h);
4983 fprintf(stderr, "Failed to commit transaction on db %s\n",
4985 ctdb_transaction_cancel(h);
4992 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5000 /* Skip whitespace */
5001 n = strspn(*ptr, " \t");
5005 /* Quoted ASCII string - no wide characters! */
5007 n = strcspn(t, "\"");
5010 ret = str_to_data(t, n, mem_ctx, data);
5017 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5021 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5028 #define MAX_LINE_SIZE 1024
5030 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5031 TDB_DATA *key, TDB_DATA *value)
5033 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5037 ptr = fgets(line, MAX_LINE_SIZE, file);
5043 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5044 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5045 /* Line Ignored but not EOF */
5051 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5053 /* Line Ignored but not EOF */
5054 talloc_free(key->dptr);
5062 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5063 int argc, const char **argv)
5065 const char *db_name;
5066 struct ctdb_db_context *db;
5067 struct ctdb_transaction_handle *h;
5070 TDB_DATA key, value;
5073 if (argc < 1 || argc > 2) {
5077 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5082 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5083 fprintf(stderr, "Transactions not supported on DB %s\n",
5089 file = fopen(argv[1], "r");
5091 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5098 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5101 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5105 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5106 TIMEOUT(), db, false, &h);
5108 fprintf(stderr, "Failed to start transaction on db %s\n",
5113 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5114 if (key.dsize != 0) {
5115 ret = ctdb_transaction_store_record(h, key, value);
5117 fprintf(stderr, "Failed to store record\n");
5118 ctdb_transaction_cancel(h);
5121 talloc_free(key.dptr);
5122 talloc_free(value.dptr);
5126 ret = ctdb_transaction_commit(h);
5128 fprintf(stderr, "Failed to commit transaction on db %s\n",
5130 ctdb_transaction_cancel(h);
5134 if (file != stdin) {
5140 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5141 int argc, const char **argv)
5143 struct tdb_context *tdb;
5145 struct ctdb_ltdb_header header;
5148 if (argc < 2 || argc > 3) {
5152 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5154 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5158 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5160 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5165 data = tdb_fetch(tdb, key);
5166 if (data.dptr == NULL) {
5167 fprintf(stderr, "No record for key %s\n", argv[1]);
5172 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5173 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5184 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5186 fprintf(stderr, "Failed to open output file %s\n",
5191 nwritten = sys_write(fd, data.dptr, data.dsize);
5192 if (nwritten != data.dsize) {
5193 fprintf(stderr, "Failed to write record to file\n");
5202 ret = ctdb_ltdb_header_extract(&data, &header);
5204 fprintf(stderr, "Failed to parse header from data\n");
5208 dump_ltdb_header(&header);
5209 dump_tdb_data("data", data);
5214 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5215 int argc, const char **argv)
5217 struct tdb_context *tdb;
5218 TDB_DATA key, data[2], value;
5219 struct ctdb_ltdb_header header;
5220 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5224 if (argc < 3 || argc > 5) {
5228 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5230 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5234 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5236 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5241 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5243 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5248 ZERO_STRUCT(header);
5251 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5254 header.dmaster = (uint32_t)atol(argv[4]);
5257 header.flags = (uint32_t)atol(argv[5]);
5260 ctdb_ltdb_header_push(&header, header_buf, &np);
5263 data[0].dptr = header_buf;
5265 data[1].dsize = value.dsize;
5266 data[1].dptr = value.dptr;
5268 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5270 fprintf(stderr, "Failed to write record %s to file %s\n",
5279 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5280 int argc, const char **argv)
5282 const char *db_name;
5283 struct ctdb_db_context *db;
5284 struct ctdb_record_handle *h;
5287 bool readonly = false;
5290 if (argc < 2 || argc > 3) {
5295 if (strcmp(argv[2], "readonly") == 0) {
5302 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5306 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5307 fprintf(stderr, "DB %s is not a volatile database\n",
5312 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5315 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5319 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5321 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5325 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5326 db, key, readonly, &h, NULL, &data);
5328 fprintf(stderr, "Failed to read record for key %s\n",
5331 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5332 (int)data.dsize, data.dptr);
5339 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5340 int argc, const char **argv)
5342 const char *db_name;
5343 struct ctdb_db_context *db;
5344 struct ctdb_record_handle *h;
5353 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5357 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5358 fprintf(stderr, "DB %s is not a volatile database\n",
5363 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5366 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5370 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5372 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5376 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5378 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5382 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5383 db, key, false, &h, NULL, NULL);
5385 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5389 ret = ctdb_store_record(h, data);
5391 fprintf(stderr, "Failed to store record for key %s\n",
5399 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5400 int argc, const char **argv)
5402 const char *db_name;
5403 struct ctdb_db_context *db;
5404 struct ctdb_record_handle *h;
5413 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5417 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5418 fprintf(stderr, "DB %s is not a volatile database\n",
5423 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5426 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5430 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5432 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5436 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5437 db, key, false, &h, NULL, &data);
5439 fprintf(stderr, "Failed to fetch record for key %s\n",
5444 ret = ctdb_delete_record(h);
5446 fprintf(stderr, "Failed to delete record for key %s\n",
5454 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5455 int argc, const char **argv)
5457 struct sockaddr_in sin;
5463 usage("chktcpport");
5466 port = atoi(argv[0]);
5468 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5470 fprintf(stderr, "Failed to open local socket\n");
5474 v = fcntl(s, F_GETFL, 0);
5475 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5476 fprintf(stderr, "Unable to set socket non-blocking\n");
5481 bzero(&sin, sizeof(sin));
5482 sin.sin_family = AF_INET;
5483 sin.sin_port = htons(port);
5484 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5487 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5494 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5495 int argc, const char **argv)
5498 const char *db_name;
5503 usage("getdbseqnum");
5506 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5510 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5511 ctdb->cmd_pnn, TIMEOUT(), db_id,
5514 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5519 printf("0x%"PRIx64"\n", seqnum);
5523 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5524 int argc, const char **argv)
5526 const char *nodestring = NULL;
5527 struct ctdb_node_map *nodemap;
5529 bool print_hdr = false;
5532 usage("nodestatus");
5536 nodestring = argv[0];
5537 if (strcmp(nodestring, "all") == 0) {
5542 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5546 if (options.machinereadable) {
5547 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5549 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5553 for (i=0; i<nodemap->num; i++) {
5554 ret |= nodemap->node[i].flags;
5563 } db_stats_fields[] = {
5564 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5565 DBSTATISTICS_FIELD(db_ro_delegations),
5566 DBSTATISTICS_FIELD(db_ro_revokes),
5567 DBSTATISTICS_FIELD(locks.num_calls),
5568 DBSTATISTICS_FIELD(locks.num_current),
5569 DBSTATISTICS_FIELD(locks.num_pending),
5570 DBSTATISTICS_FIELD(locks.num_failed),
5573 static void print_dbstatistics(const char *db_name,
5574 struct ctdb_db_statistics *s)
5577 const char *prefix = NULL;
5580 printf("DB Statistics %s\n", db_name);
5582 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5583 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5584 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5586 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5587 prefix = db_stats_fields[i].name;
5588 printf(" %*.*s\n", preflen-1, preflen-1,
5589 db_stats_fields[i].name);
5594 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5595 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5596 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5599 printf(" hop_count_buckets:");
5600 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5601 printf(" %d", s->hop_count_bucket[i]);
5605 printf(" lock_buckets:");
5606 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5607 printf(" %d", s->locks.buckets[i]);
5611 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5612 "locks_latency MIN/AVG/MAX",
5613 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5614 s->locks.latency.max, s->locks.latency.num);
5616 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5617 "vacuum_latency MIN/AVG/MAX",
5618 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5619 s->vacuum.latency.max, s->vacuum.latency.num);
5621 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5622 for (i=0; i<s->num_hot_keys; i++) {
5624 printf(" Count:%d Key:", s->hot_keys[i].count);
5625 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5626 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5632 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5633 int argc, const char **argv)
5636 const char *db_name;
5637 struct ctdb_db_statistics *dbstats;
5641 usage("dbstatistics");
5644 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5648 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5649 ctdb->cmd_pnn, TIMEOUT(), db_id,
5652 fprintf(stderr, "Failed to get statistics for DB %s\n",
5657 print_dbstatistics(db_name, dbstats);
5661 struct disable_takeover_runs_state {
5669 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5672 struct disable_takeover_runs_state *state =
5673 (struct disable_takeover_runs_state *)private_data;
5676 if (data.dsize != sizeof(int)) {
5681 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5682 ret = *(int *)data.dptr;
5684 state->status = ret;
5688 for (i=0; i<state->node_count; i++) {
5689 if (state->pnn_list[i] == ret) {
5690 state->reply[i] = true;
5696 for (i=0; i<state->node_count; i++) {
5697 if (! state->reply[i]) {
5698 state->done = false;
5704 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5705 struct ctdb_context *ctdb, uint32_t timeout,
5706 uint32_t *pnn_list, int count)
5708 struct ctdb_disable_message disable = { 0 };
5709 struct disable_takeover_runs_state state;
5712 disable.pnn = ctdb->pnn;
5713 disable.srvid = next_srvid(ctdb);
5714 disable.timeout = timeout;
5716 state.pnn_list = pnn_list;
5717 state.node_count = count;
5720 state.reply = talloc_zero_array(mem_ctx, bool, count);
5721 if (state.reply == NULL) {
5725 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5727 disable_takeover_run_handler,
5733 for (i=0; i<count; i++) {
5734 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5743 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5745 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5747 ret = (state.status >= 0 ? 0 : 1);
5751 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5752 disable.srvid, &state);
5756 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5757 int argc, const char **argv)
5759 const char *nodestring = NULL;
5760 struct ctdb_node_map *nodemap, *nodemap2;
5761 struct ctdb_req_control request;
5762 uint32_t *pnn_list, *pnn_list2;
5763 int ret, count, count2;
5770 nodestring = argv[0];
5773 nodemap = get_nodemap(ctdb, false);
5774 if (nodemap == NULL) {
5778 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5782 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5783 mem_ctx, &pnn_list);
5785 fprintf(stderr, "Memory allocation error\n");
5789 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5790 mem_ctx, &pnn_list2);
5792 fprintf(stderr, "Memory allocation error\n");
5796 /* Disable takeover runs on all connected nodes. A reply
5797 * indicating success is needed from each node so all nodes
5798 * will need to be active.
5800 * A check could be added to not allow reloading of IPs when
5801 * there are disconnected nodes. However, this should
5802 * probably be left up to the administrator.
5804 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5807 fprintf(stderr, "Failed to disable takeover runs\n");
5811 /* Now tell all the desired nodes to reload their public IPs.
5812 * Keep trying this until it succeeds. This assumes all
5813 * failures are transient, which might not be true...
5815 ctdb_req_control_reload_public_ips(&request);
5816 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5817 pnn_list2, count2, TIMEOUT(),
5818 &request, NULL, NULL);
5820 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5823 /* It isn't strictly necessary to wait until takeover runs are
5824 * re-enabled but doing so can't hurt.
5826 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5828 fprintf(stderr, "Failed to enable takeover runs\n");
5832 return ipreallocate(mem_ctx, ctdb);
5836 static const struct ctdb_cmd {
5838 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5839 bool without_daemon; /* can be run without daemon running ? */
5840 bool remote; /* can be run on remote nodes */
5843 } ctdb_commands[] = {
5844 { "version", control_version, true, false,
5845 "show version of ctdb", NULL },
5846 { "status", control_status, false, true,
5847 "show node status", NULL },
5848 { "uptime", control_uptime, false, true,
5849 "show node uptime", NULL },
5850 { "ping", control_ping, false, true,
5851 "ping a node", NULL },
5852 { "runstate", control_runstate, false, true,
5853 "get/check runstate of a node",
5854 "[setup|first_recovery|startup|running]" },
5855 { "getvar", control_getvar, false, true,
5856 "get a tunable variable", "<name>" },
5857 { "setvar", control_setvar, false, true,
5858 "set a tunable variable", "<name> <value>" },
5859 { "listvars", control_listvars, false, true,
5860 "list tunable variables", NULL },
5861 { "statistics", control_statistics, false, true,
5862 "show ctdb statistics", NULL },
5863 { "statisticsreset", control_statistics_reset, false, true,
5864 "reset ctdb statistics", NULL },
5865 { "stats", control_stats, false, true,
5866 "show rolling statistics", "[count]" },
5867 { "ip", control_ip, false, true,
5868 "show public ips", "[all]" },
5869 { "ipinfo", control_ipinfo, false, true,
5870 "show public ip details", "<ip>" },
5871 { "ifaces", control_ifaces, false, true,
5872 "show interfaces", NULL },
5873 { "setifacelink", control_setifacelink, false, true,
5874 "set interface link status", "<iface> up|down" },
5875 { "process-exists", control_process_exists, false, true,
5876 "check if a process exists on a node", "<pid> [<srvid>]" },
5877 { "getdbmap", control_getdbmap, false, true,
5878 "show attached databases", NULL },
5879 { "getdbstatus", control_getdbstatus, false, true,
5880 "show database status", "<dbname|dbid>" },
5881 { "catdb", control_catdb, false, false,
5882 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5883 { "cattdb", control_cattdb, false, false,
5884 "dump local ctdb database", "<dbname|dbid>" },
5885 { "getcapabilities", control_getcapabilities, false, true,
5886 "show node capabilities", NULL },
5887 { "pnn", control_pnn, false, false,
5888 "show the pnn of the currnet node", NULL },
5889 { "lvs", control_lvs, false, false,
5890 "show lvs configuration", "master|list|status" },
5891 { "setdebug", control_setdebug, false, true,
5892 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5893 { "getdebug", control_getdebug, false, true,
5894 "get debug level", NULL },
5895 { "attach", control_attach, false, false,
5896 "attach a database", "<dbname> [persistent|replicated]" },
5897 { "detach", control_detach, false, false,
5898 "detach database(s)", "<dbname|dbid> ..." },
5899 { "dumpmemory", control_dumpmemory, false, true,
5900 "dump ctdbd memory map", NULL },
5901 { "rddumpmemory", control_rddumpmemory, false, true,
5902 "dump recoverd memory map", NULL },
5903 { "getpid", control_getpid, false, true,
5904 "get ctdbd process ID", NULL },
5905 { "disable", control_disable, false, true,
5906 "disable a node", NULL },
5907 { "enable", control_enable, false, true,
5908 "enable a node", NULL },
5909 { "stop", control_stop, false, true,
5910 "stop a node", NULL },
5911 { "continue", control_continue, false, true,
5912 "continue a stopped node", NULL },
5913 { "ban", control_ban, false, true,
5914 "ban a node", "<bantime>"},
5915 { "unban", control_unban, false, true,
5916 "unban a node", NULL },
5917 { "shutdown", control_shutdown, false, true,
5918 "shutdown ctdb daemon", NULL },
5919 { "recover", control_recover, false, true,
5920 "force recovery", NULL },
5921 { "sync", control_ipreallocate, false, true,
5922 "run ip reallocation (deprecated)", NULL },
5923 { "ipreallocate", control_ipreallocate, false, true,
5924 "run ip reallocation", NULL },
5925 { "isnotrecmaster", control_isnotrecmaster, false, false,
5926 "check if local node is the recmaster", NULL },
5927 { "gratarp", control_gratarp, false, true,
5928 "send a gratuitous arp", "<ip> <interface>" },
5929 { "tickle", control_tickle, true, false,
5930 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5931 { "gettickles", control_gettickles, false, true,
5932 "get the list of tickles", "<ip> [<port>]" },
5933 { "addtickle", control_addtickle, false, true,
5934 "add a tickle", "<ip>:<port> <ip>:<port>" },
5935 { "deltickle", control_deltickle, false, true,
5936 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5937 { "listnodes", control_listnodes, true, true,
5938 "list nodes in the cluster", NULL },
5939 { "reloadnodes", control_reloadnodes, false, false,
5940 "reload the nodes file all nodes", NULL },
5941 { "moveip", control_moveip, false, false,
5942 "move an ip address to another node", "<ip> <node>" },
5943 { "addip", control_addip, false, true,
5944 "add an ip address to a node", "<ip/mask> <iface>" },
5945 { "delip", control_delip, false, true,
5946 "delete an ip address from a node", "<ip>" },
5947 { "backupdb", control_backupdb, false, false,
5948 "backup a database into a file", "<dbname|dbid> <file>" },
5949 { "restoredb", control_restoredb, false, false,
5950 "restore a database from a file", "<file> [dbname]" },
5951 { "dumpdbbackup", control_dumpdbbackup, true, false,
5952 "dump database from a backup file", "<file>" },
5953 { "wipedb", control_wipedb, false, false,
5954 "wipe the contents of a database.", "<dbname|dbid>"},
5955 { "recmaster", control_recmaster, false, true,
5956 "show the pnn for the recovery master", NULL },
5957 { "event", control_event, true, false,
5958 "event and event script commands", NULL },
5959 { "scriptstatus", control_scriptstatus, true, false,
5960 "show event script status",
5961 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5962 { "natgw", control_natgw, false, false,
5963 "show natgw configuration", "master|list|status" },
5964 { "getreclock", control_getreclock, false, true,
5965 "get recovery lock file", NULL },
5966 { "setlmasterrole", control_setlmasterrole, false, true,
5967 "set LMASTER role", "on|off" },
5968 { "setrecmasterrole", control_setrecmasterrole, false, true,
5969 "set RECMASTER role", "on|off"},
5970 { "setdbreadonly", control_setdbreadonly, false, true,
5971 "enable readonly records", "<dbname|dbid>" },
5972 { "setdbsticky", control_setdbsticky, false, true,
5973 "enable sticky records", "<dbname|dbid>"},
5974 { "pfetch", control_pfetch, false, false,
5975 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
5976 { "pstore", control_pstore, false, false,
5977 "write record to persistent database", "<dbname|dbid> <key> <value>" },
5978 { "pdelete", control_pdelete, false, false,
5979 "delete record from persistent database", "<dbname|dbid> <key>" },
5980 { "ptrans", control_ptrans, false, false,
5981 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
5982 { "tfetch", control_tfetch, false, true,
5983 "fetch a record", "<tdb-file> <key> [<file>]" },
5984 { "tstore", control_tstore, false, true,
5985 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
5986 { "readkey", control_readkey, false, false,
5987 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
5988 { "writekey", control_writekey, false, false,
5989 "write value for a database key", "<dbname|dbid> <key> <value>" },
5990 { "deletekey", control_deletekey, false, false,
5991 "delete a database key", "<dbname|dbid> <key>" },
5992 { "checktcpport", control_checktcpport, true, false,
5993 "check if a service is bound to a specific tcp port or not", "<port>" },
5994 { "getdbseqnum", control_getdbseqnum, false, false,
5995 "get database sequence number", "<dbname|dbid>" },
5996 { "nodestatus", control_nodestatus, false, true,
5997 "show and return node status", "[all|<pnn-list>]" },
5998 { "dbstatistics", control_dbstatistics, false, true,
5999 "show database statistics", "<dbname|dbid>" },
6000 { "reloadips", control_reloadips, false, false,
6001 "reload the public addresses file", "[all|<pnn-list>]" },
6004 static const struct ctdb_cmd *match_command(const char *command)
6006 const struct ctdb_cmd *cmd;
6009 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6010 cmd = &ctdb_commands[i];
6011 if (strlen(command) == strlen(cmd->name) &&
6012 strncmp(command, cmd->name, strlen(command)) == 0) {
6022 * Show usage message
6024 static void usage_full(void)
6028 poptPrintHelp(pc, stdout, 0);
6029 printf("\nCommands:\n");
6030 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6031 printf(" %-15s %-27s %s\n",
6032 ctdb_commands[i].name,
6033 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6034 ctdb_commands[i].msg);
6038 static void usage(const char *command)
6040 const struct ctdb_cmd *cmd;
6042 if (command == NULL) {
6047 cmd = match_command(command);
6051 poptPrintUsage(pc, stdout, 0);
6052 printf("\nCommands:\n");
6053 printf(" %-15s %-27s %s\n",
6054 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6060 struct poptOption cmdline_options[] = {
6062 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6064 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6065 "timelimit (in seconds)" },
6066 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6067 "node specification - integer" },
6068 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6069 "enable machine readable output", NULL },
6070 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6071 "specify separator for machine readable output", "CHAR" },
6072 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6073 "enable machine parsable output with separator |", NULL },
6074 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6075 "enable verbose output", NULL },
6076 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6077 "die if runtime exceeds this limit (in seconds)" },
6081 static int process_command(const struct ctdb_cmd *cmd, int argc,
6084 TALLOC_CTX *tmp_ctx;
6085 struct ctdb_context *ctdb;
6086 const char *ctdb_socket;
6089 uint64_t srvid_offset;
6091 tmp_ctx = talloc_new(NULL);
6092 if (tmp_ctx == NULL) {
6093 fprintf(stderr, "Memory allocation error\n");
6097 if (cmd->without_daemon) {
6098 if (options.pnn != -1) {
6100 "Cannot specify node for command %s\n",
6105 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6106 talloc_free(tmp_ctx);
6110 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6112 fprintf(stderr, "Memory allocation error\n");
6116 ctdb->ev = tevent_context_init(ctdb);
6117 if (ctdb->ev == NULL) {
6118 fprintf(stderr, "Failed to initialize tevent\n");
6122 ctdb_socket = getenv("CTDB_SOCKET");
6123 if (ctdb_socket == NULL) {
6124 ctdb_socket = CTDB_SOCKET;
6127 ret = ctdb_client_init(ctdb, ctdb->ev, ctdb_socket, &ctdb->client);
6129 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6132 if (!find_node_xpnn(ctdb, NULL)) {
6133 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6138 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6139 srvid_offset = getpid() & 0xFFFF;
6140 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6142 if (options.pnn != -1) {
6143 status = verify_pnn(ctdb, options.pnn);
6148 ctdb->cmd_pnn = options.pnn;
6150 ctdb->cmd_pnn = ctdb->pnn;
6153 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6154 fprintf(stderr, "Node cannot be specified for command %s\n",
6159 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6160 talloc_free(tmp_ctx);
6164 talloc_free(tmp_ctx);
6168 static void signal_handler(int sig)
6170 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6173 static void alarm_handler(int sig)
6175 /* Kill any child processes */
6176 signal(SIGTERM, signal_handler);
6182 int main(int argc, const char *argv[])
6185 const char **extra_argv;
6187 const struct ctdb_cmd *cmd;
6193 /* Set default options */
6194 options.debuglevelstr = NULL;
6195 options.timelimit = 10;
6197 options.maxruntime = 0;
6200 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6201 POPT_CONTEXT_KEEP_FIRST);
6202 while ((opt = poptGetNextOpt(pc)) != -1) {
6203 fprintf(stderr, "Invalid option %s: %s\n",
6204 poptBadOption(pc, 0), poptStrerror(opt));
6208 if (options.maxruntime == 0) {
6209 const char *ctdb_timeout;
6211 ctdb_timeout = getenv("CTDB_TIMEOUT");
6212 if (ctdb_timeout != NULL) {
6213 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6215 options.maxruntime = 120;
6218 if (options.maxruntime <= 120) {
6219 /* default timeout is 120 seconds */
6220 options.maxruntime = 120;
6223 if (options.machineparsable) {
6224 options.machinereadable = 1;
6227 /* setup the remaining options for the commands */
6229 extra_argv = poptGetArgs(pc);
6232 while (extra_argv[extra_argc]) extra_argc++;
6235 if (extra_argc < 1) {
6239 cmd = match_command(extra_argv[0]);
6241 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6245 /* Enable logging */
6246 setup_logging("ctdb", DEBUG_STDERR);
6247 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6248 DEBUGLEVEL = loglevel;
6250 DEBUGLEVEL = DEBUG_ERR;
6253 signal(SIGALRM, alarm_handler);
6254 alarm(options.maxruntime);
6256 ret = process_command(cmd, extra_argc, extra_argv);
6261 (void)poptFreeContext(pc);