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.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)
54 const char *debuglevelstr;
62 int printemptyrecords;
69 static poptContext pc;
72 struct tevent_context *ev;
73 struct ctdb_client_context *client;
74 struct ctdb_node_map *nodemap;
75 uint32_t pnn, cmd_pnn;
79 static void usage(const char *command);
85 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
87 return (tv2->tv_sec - tv->tv_sec) +
88 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
91 static struct ctdb_node_and_flags *get_node_by_pnn(
92 struct ctdb_node_map *nodemap,
97 for (i=0; i<nodemap->num; i++) {
98 if (nodemap->node[i].pnn == pnn) {
99 return &nodemap->node[i];
105 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
107 static const struct {
111 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
112 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
113 { NODE_FLAGS_BANNED, "BANNED" },
114 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
115 { NODE_FLAGS_DELETED, "DELETED" },
116 { NODE_FLAGS_STOPPED, "STOPPED" },
117 { NODE_FLAGS_INACTIVE, "INACTIVE" },
119 char *flags_str = NULL;
122 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
123 if (flags & flag_names[i].flag) {
124 if (flags_str == NULL) {
125 flags_str = talloc_asprintf(mem_ctx,
126 "%s", flag_names[i].name);
128 flags_str = talloc_asprintf_append(flags_str,
129 "|%s", flag_names[i].name);
131 if (flags_str == NULL) {
132 return "OUT-OF-MEMORY";
136 if (flags_str == NULL) {
143 static uint64_t next_srvid(struct ctdb_context *ctdb)
150 * Get consistent nodemap information.
152 * If nodemap is already cached, use that. If not get it.
153 * If the current node is BANNED, then get nodemap from "better" node.
155 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
158 struct ctdb_node_map *nodemap;
159 struct ctdb_node_and_flags *node;
160 uint32_t current_node;
164 TALLOC_FREE(ctdb->nodemap);
167 if (ctdb->nodemap != NULL) {
168 return ctdb->nodemap;
171 tmp_ctx = talloc_new(ctdb);
172 if (tmp_ctx == NULL) {
176 current_node = ctdb->pnn;
178 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
179 current_node, TIMEOUT(), &nodemap);
181 fprintf(stderr, "Failed to get nodemap from node %u\n",
186 node = get_node_by_pnn(nodemap, current_node);
187 if (node->flags & NODE_FLAGS_BANNED) {
190 current_node = (current_node + 1) % nodemap->num;
191 node = get_node_by_pnn(nodemap, current_node);
193 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
196 } while (current_node != ctdb->pnn);
198 if (current_node == ctdb->pnn) {
199 /* Tried all nodes in the cluster */
200 fprintf(stderr, "Warning: All nodes are banned.\n");
207 ctdb->nodemap = talloc_steal(ctdb, nodemap);
211 talloc_free(tmp_ctx);
215 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
217 struct ctdb_node_map *nodemap;
225 nodemap = get_nodemap(ctdb, false);
226 if (nodemap == NULL) {
231 for (i=0; i<nodemap->num; i++) {
232 if (nodemap->node[i].pnn == pnn) {
238 fprintf(stderr, "Node %u does not exist\n", pnn);
242 if (nodemap->node[i].flags &
243 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
244 fprintf(stderr, "Node %u has status %s\n", pnn,
245 pretty_print_flags(ctdb, nodemap->node[i].flags));
252 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
253 struct ctdb_node_map *nodemap)
255 struct ctdb_node_map *nodemap2;
257 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
258 if (nodemap2 == NULL) {
262 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
264 if (nodemap2->node == NULL) {
265 talloc_free(nodemap2);
273 * Get the number and the list of matching nodes
275 * nodestring := NULL | all | pnn,[pnn,...]
277 * If nodestring is NULL, use the current node.
279 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
280 const char *nodestring,
281 struct ctdb_node_map **out)
283 struct ctdb_node_map *nodemap, *nodemap2;
284 struct ctdb_node_and_flags *node;
287 nodemap = get_nodemap(ctdb, false);
288 if (nodemap == NULL) {
292 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
293 if (nodemap2 == NULL) {
297 if (nodestring == NULL) {
298 for (i=0; i<nodemap->num; i++) {
299 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
300 nodemap2->node[0] = nodemap->node[i];
309 if (strcmp(nodestring, "all") == 0) {
310 for (i=0; i<nodemap->num; i++) {
311 nodemap2->node[i] = nodemap->node[i];
313 nodemap2->num = nodemap->num;
319 ns = talloc_strdup(mem_ctx, nodestring);
324 tok = strtok(ns, ",");
325 while (tok != NULL) {
329 pnn = (uint32_t)strtoul(tok, &endptr, 0);
330 if (pnn == 0 && tok == endptr) {
331 fprintf(stderr, "Invalid node %s\n", tok);
335 node = get_node_by_pnn(nodemap, pnn);
337 fprintf(stderr, "Node %u does not exist\n",
342 nodemap2->node[nodemap2->num] = *node;
345 tok = strtok(NULL, ",");
354 /* Compare IP address */
355 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
359 if (ip1->sa.sa_family != ip2->sa.sa_family) {
363 switch (ip1->sa.sa_family) {
365 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
366 sizeof(struct in_addr)) == 0);
370 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
371 sizeof(struct in6_addr)) == 0);
378 /* Append a node to a node map with given address and flags */
379 static bool node_map_add(struct ctdb_node_map *nodemap,
380 const char *nstr, uint32_t flags)
384 struct ctdb_node_and_flags *n;
387 ret = ctdb_sock_addr_from_string(nstr, &addr, false);
389 fprintf(stderr, "Invalid IP address %s\n", nstr);
394 nodemap->node = talloc_realloc(nodemap, nodemap->node,
395 struct ctdb_node_and_flags, num+1);
396 if (nodemap->node == NULL) {
400 n = &nodemap->node[num];
405 nodemap->num = num+1;
409 /* Read a nodes file into a node map */
410 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
416 struct ctdb_node_map *nodemap;
418 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
419 if (nodemap == NULL) {
423 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
428 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
432 for (i=0; i<nlines; i++) {
438 /* strip leading spaces */
439 while((*node == ' ') || (*node == '\t')) {
445 /* strip trailing spaces */
447 ((node[len-1] == ' ') || (node[len-1] == '\t')))
457 /* A "deleted" node is a node that is
458 commented out in the nodes file. This is
459 used instead of removing a line, which
460 would cause subsequent nodes to change
462 flags = NODE_FLAGS_DELETED;
463 node = discard_const("0.0.0.0");
467 if (! node_map_add(nodemap, node, flags)) {
469 TALLOC_FREE(nodemap);
478 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
480 struct ctdb_node_map *nodemap;
482 const char *nodes_list = NULL;
484 if (pnn != CTDB_UNKNOWN_PNN) {
485 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
486 if (nodepath != NULL) {
487 nodes_list = getenv(nodepath);
490 if (nodes_list == NULL) {
491 nodes_list = getenv("CTDB_NODES");
493 if (nodes_list == NULL) {
494 const char *basedir = getenv("CTDB_BASE");
495 if (basedir == NULL) {
496 basedir = CTDB_ETCDIR;
498 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
499 if (nodes_list == NULL) {
500 fprintf(stderr, "Memory allocation error\n");
505 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
506 if (nodemap == NULL) {
507 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
515 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
516 struct ctdb_context *ctdb,
517 struct ctdb_dbid_map *dbmap,
520 struct ctdb_dbid *db = NULL;
524 for (i=0; i<dbmap->num; i++) {
525 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
526 ctdb->pnn, TIMEOUT(),
527 dbmap->dbs[i].db_id, &name);
532 if (strcmp(db_name, name) == 0) {
533 talloc_free(discard_const(name));
542 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
543 const char *db_arg, uint32_t *db_id,
544 const char **db_name, uint8_t *db_flags)
546 struct ctdb_dbid_map *dbmap;
547 struct ctdb_dbid *db = NULL;
549 const char *name = NULL;
552 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
553 ctdb->pnn, TIMEOUT(), &dbmap);
558 if (strncmp(db_arg, "0x", 2) == 0) {
559 id = strtoul(db_arg, NULL, 0);
560 for (i=0; i<dbmap->num; i++) {
561 if (id == dbmap->dbs[i].db_id) {
568 db = db_find(mem_ctx, ctdb, dbmap, name);
572 fprintf(stderr, "No database matching '%s' found\n", db_arg);
577 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
578 ctdb->pnn, TIMEOUT(), id, &name);
587 if (db_name != NULL) {
588 *db_name = talloc_strdup(mem_ctx, name);
590 if (db_flags != NULL) {
591 *db_flags = db->flags;
596 static int h2i(char h)
598 if (h >= 'a' && h <= 'f') {
601 if (h >= 'A' && h <= 'F') {
607 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
614 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
619 data.dsize = len / 2;
620 data.dptr = talloc_size(mem_ctx, data.dsize);
621 if (data.dptr == NULL) {
625 for (i=0; i<data.dsize; i++) {
626 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
633 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
639 if (strncmp(str, "0x", 2) == 0) {
640 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
642 data.dptr = talloc_memdup(mem_ctx, str, len);
643 if (data.dptr == NULL) {
653 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
654 const char *path, int argc, const char **argv)
657 int save_errno, status, ret;
658 const char **new_argv;
661 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
662 if (new_argv == NULL) {
667 for (i=0; i<argc; i++) {
668 new_argv[i+1] = argv[i];
670 new_argv[argc+1] = NULL;
675 talloc_free(new_argv);
676 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
677 command, path, strerror(save_errno));
682 ret = execv(path, discard_const(new_argv));
686 /* Should not happen */
690 talloc_free(new_argv);
692 ret = waitpid(pid, &status, 0);
695 fprintf(stderr, "waitpid() failed for %s - %s\n",
696 command, strerror(save_errno));
700 if (WIFEXITED(status)) {
701 int pstatus = WEXITSTATUS(status);
702 if (WIFSIGNALED(status)) {
703 fprintf(stderr, "%s terminated with signal %d\n",
704 command, WTERMSIG(status));
706 } else if (pstatus >= 64 && pstatus < 255) {
707 fprintf(stderr, "%s failed with error %d\n",
708 command, pstatus-64);
714 } else if (WIFSIGNALED(status)) {
715 fprintf(stderr, "%s terminated with signal %d\n",
716 command, WTERMSIG(status));
727 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
728 int argc, const char **argv)
730 printf("%s\n", ctdb_version_string);
734 static bool partially_online(TALLOC_CTX *mem_ctx,
735 struct ctdb_context *ctdb,
736 struct ctdb_node_and_flags *node)
738 struct ctdb_iface_list *iface_list;
742 if (node->flags != 0) {
746 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
747 node->pnn, TIMEOUT(), &iface_list);
753 for (i=0; i < iface_list->num; i++) {
754 if (iface_list->iface[i].link_state == 0) {
763 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
764 struct ctdb_context *ctdb,
765 struct ctdb_node_map *nodemap,
768 struct ctdb_node_and_flags *node;
771 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
775 "Disconnected", options.sep,
776 "Banned", options.sep,
777 "Disabled", options.sep,
778 "Unhealthy", options.sep,
779 "Stopped", options.sep,
780 "Inactive", options.sep,
781 "PartiallyOnline", options.sep,
782 "ThisNode", options.sep);
784 for (i=0; i<nodemap->num; i++) {
785 node = &nodemap->node[i];
786 if (node->flags & NODE_FLAGS_DELETED) {
790 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
792 node->pnn, options.sep,
793 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
795 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
796 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
797 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
799 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
800 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
801 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
802 partially_online(mem_ctx, ctdb, node), options.sep,
803 (node->pnn == mypnn)?'Y':'N', options.sep);
808 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
809 struct ctdb_node_map *nodemap, uint32_t mypnn,
812 struct ctdb_node_and_flags *node;
813 int num_deleted_nodes = 0;
816 for (i=0; i<nodemap->num; i++) {
817 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
823 if (num_deleted_nodes == 0) {
824 printf("Number of nodes:%d\n", nodemap->num);
826 printf("Number of nodes:%d "
827 "(including %d deleted nodes)\n",
828 nodemap->num, num_deleted_nodes);
832 for (i=0; i<nodemap->num; i++) {
833 node = &nodemap->node[i];
834 if (node->flags & NODE_FLAGS_DELETED) {
838 printf("pnn:%u %-16s %s%s\n",
840 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
841 partially_online(mem_ctx, ctdb, node) ?
843 pretty_print_flags(mem_ctx, node->flags),
844 node->pnn == mypnn ? " (THIS NODE)" : "");
848 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
849 struct ctdb_node_map *nodemap, uint32_t mypnn,
850 struct ctdb_vnn_map *vnnmap, int recmode,
855 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
857 if (vnnmap->generation == INVALID_GENERATION) {
858 printf("Generation:INVALID\n");
860 printf("Generation:%u\n", vnnmap->generation);
862 printf("Size:%d\n", vnnmap->size);
863 for (i=0; i<vnnmap->size; i++) {
864 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
867 printf("Recovery mode:%s (%d)\n",
868 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
870 printf("Recovery master:%d\n", recmaster);
873 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
874 int argc, const char **argv)
876 struct ctdb_node_map *nodemap;
877 struct ctdb_vnn_map *vnnmap;
886 nodemap = get_nodemap(ctdb, false);
887 if (nodemap == NULL) {
891 if (options.machinereadable == 1) {
892 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
896 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
897 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
902 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
903 ctdb->cmd_pnn, TIMEOUT(), &recmode);
908 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
909 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
914 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
919 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
920 int argc, const char **argv)
922 struct ctdb_uptime *uptime;
923 int ret, tmp, days, hours, minutes, seconds;
925 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
926 ctdb->cmd_pnn, TIMEOUT(), &uptime);
931 printf("Current time of node %-4u : %s",
932 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
934 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
935 seconds = tmp % 60; tmp /= 60;
936 minutes = tmp % 60; tmp /= 60;
937 hours = tmp % 24; tmp /= 24;
940 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
941 days, hours, minutes, seconds,
942 ctime(&uptime->ctdbd_start_time.tv_sec));
944 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
945 seconds = tmp % 60; tmp /= 60;
946 minutes = tmp % 60; tmp /= 60;
947 hours = tmp % 24; tmp /= 24;
950 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
951 days, hours, minutes, seconds,
952 ctime(&uptime->last_recovery_finished.tv_sec));
954 printf("Duration of last recovery/failover: %lf seconds\n",
955 timeval_delta(&uptime->last_recovery_finished,
956 &uptime->last_recovery_started));
961 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
962 int argc, const char **argv)
965 int ret, num_clients;
967 tv = timeval_current();
968 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
969 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
974 printf("response from %u time=%.6f sec (%d clients)\n",
975 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
979 const char *runstate_to_string(enum ctdb_runstate runstate);
980 enum ctdb_runstate runstate_from_string(const char *runstate_str);
982 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
983 int argc, const char **argv)
985 enum ctdb_runstate runstate;
989 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
990 ctdb->cmd_pnn, TIMEOUT(), &runstate);
996 for (i=0; i<argc; i++) {
997 enum ctdb_runstate t;
1000 t = ctdb_runstate_from_string(argv[i]);
1001 if (t == CTDB_RUNSTATE_UNKNOWN) {
1002 printf("Invalid run state (%s)\n", argv[i]);
1006 if (t == runstate) {
1013 printf("CTDB not in required run state (got %s)\n",
1014 ctdb_runstate_to_string(runstate));
1018 printf("%s\n", ctdb_runstate_to_string(runstate));
1022 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1023 int argc, const char **argv)
1025 struct ctdb_var_list *tun_var_list;
1034 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1035 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1038 "Failed to get list of variables from node %u\n",
1044 for (i=0; i<tun_var_list->count; i++) {
1045 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1052 printf("No such tunable %s\n", argv[0]);
1056 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1057 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1062 printf("%-26s = %u\n", argv[0], value);
1066 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1067 int argc, const char **argv)
1069 struct ctdb_var_list *tun_var_list;
1070 struct ctdb_tunable tunable;
1078 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1079 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1082 "Failed to get list of variables from node %u\n",
1088 for (i=0; i<tun_var_list->count; i++) {
1089 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1096 printf("No such tunable %s\n", argv[0]);
1100 tunable.name = argv[0];
1101 tunable.value = strtoul(argv[1], NULL, 0);
1103 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1104 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1108 "Setting obsolete tunable variable '%s'\n",
1117 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1118 int argc, const char **argv)
1120 struct ctdb_var_list *tun_var_list;
1127 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1128 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1133 for (i=0; i<tun_var_list->count; i++) {
1134 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1143 } stats_fields[] = {
1144 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1145 STATISTICS_FIELD(num_clients),
1146 STATISTICS_FIELD(frozen),
1147 STATISTICS_FIELD(recovering),
1148 STATISTICS_FIELD(num_recoveries),
1149 STATISTICS_FIELD(client_packets_sent),
1150 STATISTICS_FIELD(client_packets_recv),
1151 STATISTICS_FIELD(node_packets_sent),
1152 STATISTICS_FIELD(node_packets_recv),
1153 STATISTICS_FIELD(keepalive_packets_sent),
1154 STATISTICS_FIELD(keepalive_packets_recv),
1155 STATISTICS_FIELD(node.req_call),
1156 STATISTICS_FIELD(node.reply_call),
1157 STATISTICS_FIELD(node.req_dmaster),
1158 STATISTICS_FIELD(node.reply_dmaster),
1159 STATISTICS_FIELD(node.reply_error),
1160 STATISTICS_FIELD(node.req_message),
1161 STATISTICS_FIELD(node.req_control),
1162 STATISTICS_FIELD(node.reply_control),
1163 STATISTICS_FIELD(node.req_tunnel),
1164 STATISTICS_FIELD(client.req_call),
1165 STATISTICS_FIELD(client.req_message),
1166 STATISTICS_FIELD(client.req_control),
1167 STATISTICS_FIELD(client.req_tunnel),
1168 STATISTICS_FIELD(timeouts.call),
1169 STATISTICS_FIELD(timeouts.control),
1170 STATISTICS_FIELD(timeouts.traverse),
1171 STATISTICS_FIELD(locks.num_calls),
1172 STATISTICS_FIELD(locks.num_current),
1173 STATISTICS_FIELD(locks.num_pending),
1174 STATISTICS_FIELD(locks.num_failed),
1175 STATISTICS_FIELD(total_calls),
1176 STATISTICS_FIELD(pending_calls),
1177 STATISTICS_FIELD(childwrite_calls),
1178 STATISTICS_FIELD(pending_childwrite_calls),
1179 STATISTICS_FIELD(memory_used),
1180 STATISTICS_FIELD(max_hop_count),
1181 STATISTICS_FIELD(total_ro_delegations),
1182 STATISTICS_FIELD(total_ro_revokes),
1185 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1187 static void print_statistics_machine(struct ctdb_statistics *s,
1193 printf("CTDB version%s", options.sep);
1194 printf("Current time of statistics%s", options.sep);
1195 printf("Statistics collected since%s", options.sep);
1196 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1197 printf("%s%s", stats_fields[i].name, options.sep);
1199 printf("num_reclock_ctdbd_latency%s", options.sep);
1200 printf("min_reclock_ctdbd_latency%s", options.sep);
1201 printf("avg_reclock_ctdbd_latency%s", options.sep);
1202 printf("max_reclock_ctdbd_latency%s", options.sep);
1204 printf("num_reclock_recd_latency%s", options.sep);
1205 printf("min_reclock_recd_latency%s", options.sep);
1206 printf("avg_reclock_recd_latency%s", options.sep);
1207 printf("max_reclock_recd_latency%s", options.sep);
1209 printf("num_call_latency%s", options.sep);
1210 printf("min_call_latency%s", options.sep);
1211 printf("avg_call_latency%s", options.sep);
1212 printf("max_call_latency%s", options.sep);
1214 printf("num_lockwait_latency%s", options.sep);
1215 printf("min_lockwait_latency%s", options.sep);
1216 printf("avg_lockwait_latency%s", options.sep);
1217 printf("max_lockwait_latency%s", options.sep);
1219 printf("num_childwrite_latency%s", options.sep);
1220 printf("min_childwrite_latency%s", options.sep);
1221 printf("avg_childwrite_latency%s", options.sep);
1222 printf("max_childwrite_latency%s", options.sep);
1226 printf("%u%s", CTDB_PROTOCOL, options.sep);
1227 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1228 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1229 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1231 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1234 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1235 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1236 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1237 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1239 printf("%u%s", s->reclock.recd.num, options.sep);
1240 printf("%.6f%s", s->reclock.recd.min, options.sep);
1241 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1242 printf("%.6f%s", s->reclock.recd.max, options.sep);
1244 printf("%d%s", s->call_latency.num, options.sep);
1245 printf("%.6f%s", s->call_latency.min, options.sep);
1246 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1247 printf("%.6f%s", s->call_latency.max, options.sep);
1249 printf("%d%s", s->childwrite_latency.num, options.sep);
1250 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1251 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1252 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1256 static void print_statistics(struct ctdb_statistics *s)
1258 int tmp, days, hours, minutes, seconds;
1260 const char *prefix = NULL;
1263 tmp = s->statistics_current_time.tv_sec -
1264 s->statistics_start_time.tv_sec;
1265 seconds = tmp % 60; tmp /= 60;
1266 minutes = tmp % 60; tmp /= 60;
1267 hours = tmp % 24; tmp /= 24;
1270 printf("CTDB version %u\n", CTDB_PROTOCOL);
1271 printf("Current time of statistics : %s",
1272 ctime(&s->statistics_current_time.tv_sec));
1273 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1274 days, hours, minutes, seconds,
1275 ctime(&s->statistics_start_time.tv_sec));
1277 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1278 if (strchr(stats_fields[i].name, '.') != NULL) {
1279 preflen = strcspn(stats_fields[i].name, ".") + 1;
1281 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1282 prefix = stats_fields[i].name;
1283 printf(" %*.*s\n", preflen-1, preflen-1,
1284 stats_fields[i].name);
1289 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1290 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1291 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1294 printf(" hop_count_buckets:");
1295 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1296 printf(" %d", s->hop_count_bucket[i]);
1299 printf(" lock_buckets:");
1300 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1301 printf(" %d", s->locks.buckets[i]);
1304 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1305 "locks_latency MIN/AVG/MAX",
1306 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1307 s->locks.latency.max, s->locks.latency.num);
1309 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1310 "reclock_ctdbd MIN/AVG/MAX",
1311 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1312 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1314 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1315 "reclock_recd MIN/AVG/MAX",
1316 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1317 s->reclock.recd.max, s->reclock.recd.num);
1319 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1320 "call_latency MIN/AVG/MAX",
1321 s->call_latency.min, LATENCY_AVG(s->call_latency),
1322 s->call_latency.max, s->call_latency.num);
1324 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1325 "childwrite_latency MIN/AVG/MAX",
1326 s->childwrite_latency.min,
1327 LATENCY_AVG(s->childwrite_latency),
1328 s->childwrite_latency.max, s->childwrite_latency.num);
1331 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1332 int argc, const char **argv)
1334 struct ctdb_statistics *stats;
1338 usage("statistics");
1341 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1342 ctdb->cmd_pnn, TIMEOUT(), &stats);
1347 if (options.machinereadable) {
1348 print_statistics_machine(stats, true);
1350 print_statistics(stats);
1356 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1357 struct ctdb_context *ctdb,
1358 int argc, const char **argv)
1363 usage("statisticsreset");
1366 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1367 ctdb->cmd_pnn, TIMEOUT());
1375 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1376 int argc, const char **argv)
1378 struct ctdb_statistics_list *slist;
1379 int ret, count = 0, i;
1380 bool show_header = true;
1387 count = atoi(argv[0]);
1390 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1391 ctdb->cmd_pnn, TIMEOUT(), &slist);
1396 for (i=0; i<slist->num; i++) {
1397 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1400 if (options.machinereadable == 1) {
1401 print_statistics_machine(&slist->stats[i],
1403 show_header = false;
1405 print_statistics(&slist->stats[i]);
1407 if (count > 0 && i == count) {
1415 static int ctdb_public_ip_cmp(const void *a, const void *b)
1417 const struct ctdb_public_ip *ip_a = a;
1418 const struct ctdb_public_ip *ip_b = b;
1420 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1423 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1424 struct ctdb_public_ip_list *ips,
1425 struct ctdb_public_ip_info **ipinfo,
1429 char *conf, *avail, *active;
1431 if (options.machinereadable == 1) {
1432 printf("%s%s%s%s%s", options.sep,
1433 "Public IP", options.sep,
1434 "Node", options.sep);
1435 if (options.verbose == 1) {
1436 printf("%s%s%s%s%s%s\n",
1437 "ActiveInterfaces", options.sep,
1438 "AvailableInterfaces", options.sep,
1439 "ConfiguredInterfaces", options.sep);
1445 printf("Public IPs on ALL nodes\n");
1447 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1451 for (i = 0; i < ips->num; i++) {
1453 if (options.machinereadable == 1) {
1454 printf("%s%s%s%d%s", options.sep,
1455 ctdb_sock_addr_to_string(
1456 mem_ctx, &ips->ip[i].addr, false),
1458 (int)ips->ip[i].pnn, options.sep);
1460 printf("%s", ctdb_sock_addr_to_string(
1461 mem_ctx, &ips->ip[i].addr, false));
1464 if (options.verbose == 0) {
1465 if (options.machinereadable == 1) {
1468 printf(" %d\n", (int)ips->ip[i].pnn);
1477 if (ipinfo[i] == NULL) {
1481 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1482 struct ctdb_iface *iface;
1484 iface = &ipinfo[i]->ifaces->iface[j];
1486 conf = talloc_strdup(mem_ctx, iface->name);
1488 conf = talloc_asprintf_append(
1489 conf, ",%s", iface->name);
1492 if (ipinfo[i]->active_idx == j) {
1493 active = iface->name;
1496 if (iface->link_state == 0) {
1500 if (avail == NULL) {
1501 avail = talloc_strdup(mem_ctx, iface->name);
1503 avail = talloc_asprintf_append(
1504 avail, ",%s", iface->name);
1510 if (options.machinereadable == 1) {
1511 printf("%s%s%s%s%s%s\n",
1512 active ? active : "", options.sep,
1513 avail ? avail : "", options.sep,
1514 conf ? conf : "", options.sep);
1516 printf(" node[%d] active[%s] available[%s]"
1517 " configured[%s]\n",
1518 (int)ips->ip[i].pnn, active ? active : "",
1519 avail ? avail : "", conf ? conf : "");
1524 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1525 size_t datalen, void *private_data)
1527 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1528 private_data, struct ctdb_public_ip_list);
1529 struct ctdb_public_ip *ip;
1531 ip = (struct ctdb_public_ip *)databuf;
1532 ips->ip[ips->num] = *ip;
1538 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1539 struct ctdb_public_ip_list **out)
1541 struct ctdb_node_map *nodemap;
1542 struct ctdb_public_ip_list *ips;
1543 struct db_hash_context *ipdb;
1545 int ret, count, i, j;
1547 nodemap = get_nodemap(ctdb, false);
1548 if (nodemap == NULL) {
1552 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1557 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1563 for (i=0; i<count; i++) {
1564 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1565 pnn_list[i], TIMEOUT(),
1571 for (j=0; j<ips->num; j++) {
1572 struct ctdb_public_ip ip;
1574 ip.pnn = ips->ip[j].pnn;
1575 ip.addr = ips->ip[j].addr;
1577 if (pnn_list[i] == ip.pnn) {
1578 /* Node claims IP is hosted on it, so
1579 * save that information
1581 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1583 (uint8_t *)&ip, sizeof(ip));
1588 /* Node thinks IP is hosted elsewhere,
1589 * so overwrite with CTDB_UNKNOWN_PNN
1590 * if there's no existing entry
1592 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1594 if (ret == ENOENT) {
1595 ip.pnn = CTDB_UNKNOWN_PNN;
1596 ret = db_hash_add(ipdb,
1597 (uint8_t *)&ip.addr,
1611 talloc_free(pnn_list);
1613 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1618 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1623 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1624 if (ips->ip == NULL) {
1628 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1633 if (count != ips->num) {
1647 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1648 int argc, const char **argv)
1650 struct ctdb_public_ip_list *ips;
1651 struct ctdb_public_ip_info **ipinfo;
1653 bool do_all = false;
1660 if (strcmp(argv[0], "all") == 0) {
1668 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1670 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1671 ctdb->cmd_pnn, TIMEOUT(),
1678 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1679 ctdb_public_ip_cmp);
1681 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1682 if (ipinfo == NULL) {
1686 for (i=0; i<ips->num; i++) {
1689 pnn = ips->ip[i].pnn;
1691 pnn = ctdb->cmd_pnn;
1693 if (pnn == CTDB_UNKNOWN_PNN) {
1697 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1699 TIMEOUT(), &ips->ip[i].addr,
1706 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1710 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1711 int argc, const char **argv)
1713 struct ctdb_public_ip_info *ipinfo;
1714 ctdb_sock_addr addr;
1721 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
1723 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1727 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1728 ctdb->cmd_pnn, TIMEOUT(), &addr,
1732 printf("Node %u does not know about IP %s\n",
1733 ctdb->cmd_pnn, argv[0]);
1738 printf("Public IP[%s] info on node %u\n",
1739 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1742 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1743 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1744 ipinfo->ip.pnn, ipinfo->ifaces->num);
1746 for (i=0; i<ipinfo->ifaces->num; i++) {
1747 struct ctdb_iface *iface;
1749 iface = &ipinfo->ifaces->iface[i];
1750 iface->name[CTDB_IFACE_SIZE] = '\0';
1751 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1753 iface->link_state == 0 ? "down" : "up",
1755 (i == ipinfo->active_idx) ? " (active)" : "");
1761 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1762 int argc, const char **argv)
1764 struct ctdb_iface_list *ifaces;
1771 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1772 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1777 if (ifaces->num == 0) {
1778 printf("No interfaces configured on node %u\n",
1783 if (options.machinereadable) {
1784 printf("%s%s%s%s%s%s%s\n", options.sep,
1785 "Name", options.sep,
1786 "LinkStatus", options.sep,
1787 "References", options.sep);
1789 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1792 for (i=0; i<ifaces->num; i++) {
1793 if (options.machinereadable) {
1794 printf("%s%s%s%u%s%u%s\n", options.sep,
1795 ifaces->iface[i].name, options.sep,
1796 ifaces->iface[i].link_state, options.sep,
1797 ifaces->iface[i].references, options.sep);
1799 printf("name:%s link:%s references:%u\n",
1800 ifaces->iface[i].name,
1801 ifaces->iface[i].link_state ? "up" : "down",
1802 ifaces->iface[i].references);
1809 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1810 int argc, const char **argv)
1812 struct ctdb_iface_list *ifaces;
1813 struct ctdb_iface *iface;
1817 usage("setifacelink");
1820 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1821 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1825 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1826 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1829 "Failed to get interface information from node %u\n",
1835 for (i=0; i<ifaces->num; i++) {
1836 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1837 iface = &ifaces->iface[i];
1842 if (iface == NULL) {
1843 printf("Interface %s not configured on node %u\n",
1844 argv[0], ctdb->cmd_pnn);
1848 if (strcmp(argv[1], "up") == 0) {
1849 iface->link_state = 1;
1850 } else if (strcmp(argv[1], "down") == 0) {
1851 iface->link_state = 0;
1853 usage("setifacelink");
1857 iface->references = 0;
1859 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1860 ctdb->cmd_pnn, TIMEOUT(), iface);
1868 static int control_process_exists(TALLOC_CTX *mem_ctx,
1869 struct ctdb_context *ctdb,
1870 int argc, const char **argv)
1876 if (argc != 1 && argc != 2) {
1877 usage("process-exists");
1880 pid = atoi(argv[0]);
1882 srvid = strtoull(argv[1], NULL, 0);
1886 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1887 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1889 struct ctdb_pid_srvid pid_srvid;
1891 pid_srvid.pid = pid;
1892 pid_srvid.srvid = srvid;
1894 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
1895 ctdb->client, ctdb->cmd_pnn,
1896 TIMEOUT(), &pid_srvid,
1905 printf("PID %d %s\n", pid,
1906 (status == 0 ? "exists" : "does not exist"));
1908 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
1909 (status == 0 ? "exists" : "does not exist"));
1914 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1915 int argc, const char **argv)
1917 struct ctdb_dbid_map *dbmap;
1924 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1925 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1930 if (options.machinereadable == 1) {
1931 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1934 "Name", options.sep,
1935 "Path", options.sep,
1936 "Persistent", options.sep,
1937 "Sticky", options.sep,
1938 "Unhealthy", options.sep,
1939 "Readonly", options.sep,
1940 "Replicated", options.sep);
1942 printf("Number of databases:%d\n", dbmap->num);
1945 for (i=0; i<dbmap->num; i++) {
1955 db_id = dbmap->dbs[i].db_id;
1957 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1958 ctdb->cmd_pnn, TIMEOUT(), db_id,
1964 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1965 ctdb->cmd_pnn, TIMEOUT(), db_id,
1971 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1972 ctdb->cmd_pnn, TIMEOUT(), db_id,
1978 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1979 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1980 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1981 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
1983 if (options.machinereadable == 1) {
1984 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1989 !! (persistent), options.sep,
1990 !! (sticky), options.sep,
1991 !! (health), options.sep,
1992 !! (readonly), options.sep,
1993 !! (replicated), options.sep);
1995 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1997 persistent ? " PERSISTENT" : "",
1998 sticky ? " STICKY" : "",
1999 readonly ? " READONLY" : "",
2000 replicated ? " REPLICATED" : "",
2001 health ? " UNHEALTHY" : "");
2004 talloc_free(discard_const(name));
2005 talloc_free(discard_const(path));
2006 talloc_free(discard_const(health));
2012 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2013 int argc, const char **argv)
2016 const char *db_name, *db_path, *db_health;
2021 usage("getdbstatus");
2024 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2028 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2029 ctdb->cmd_pnn, TIMEOUT(), db_id,
2035 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2036 ctdb->cmd_pnn, TIMEOUT(), db_id,
2042 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2043 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2044 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2045 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2046 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2047 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2048 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2052 struct dump_record_state {
2056 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2058 static void dump_tdb_data(const char *name, TDB_DATA val)
2062 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2063 for (i=0; i<val.dsize; i++) {
2064 if (ISASCII(val.dptr[i])) {
2065 fprintf(stdout, "%c", val.dptr[i]);
2067 fprintf(stdout, "\\%02X", val.dptr[i]);
2070 fprintf(stdout, "\"\n");
2073 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2075 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2076 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2077 fprintf(stdout, "flags: 0x%08x", header->flags);
2078 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2079 fprintf(stdout, " MIGRATED_WITH_DATA");
2081 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2082 fprintf(stdout, " VACUUM_MIGRATED");
2084 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2085 fprintf(stdout, " AUTOMATIC");
2087 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2088 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2090 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2091 fprintf(stdout, " RO_HAVE_READONLY");
2093 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2094 fprintf(stdout, " RO_REVOKING_READONLY");
2096 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2097 fprintf(stdout, " RO_REVOKE_COMPLETE");
2099 fprintf(stdout, "\n");
2103 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2104 TDB_DATA key, TDB_DATA data, void *private_data)
2106 struct dump_record_state *state =
2107 (struct dump_record_state *)private_data;
2111 dump_tdb_data("key", key);
2112 dump_ltdb_header(header);
2113 dump_tdb_data("data", data);
2114 fprintf(stdout, "\n");
2119 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2120 int argc, const char **argv)
2122 struct ctdb_db_context *db;
2123 const char *db_name;
2126 struct dump_record_state state;
2133 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2137 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2140 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2146 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2147 ctdb->cmd_pnn, TIMEOUT(),
2148 dump_record, &state);
2150 printf("Dumped %u records\n", state.count);
2155 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2156 int argc, const char **argv)
2158 struct ctdb_db_context *db;
2159 const char *db_name;
2162 struct dump_record_state state;
2169 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2173 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2176 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2181 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2183 printf("Dumped %u record(s)\n", state.count);
2188 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2189 struct ctdb_context *ctdb,
2190 int argc, const char **argv)
2196 usage("getcapabilities");
2199 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2200 ctdb->cmd_pnn, TIMEOUT(), &caps);
2205 if (options.machinereadable == 1) {
2206 printf("%s%s%s%s%s\n",
2208 "RECMASTER", options.sep,
2209 "LMASTER", options.sep);
2210 printf("%s%d%s%d%s\n", options.sep,
2211 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2212 !! (caps & CTDB_CAP_LMASTER), options.sep);
2214 printf("RECMASTER: %s\n",
2215 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2216 printf("LMASTER: %s\n",
2217 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2223 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2224 int argc, const char **argv)
2226 printf("%u\n", ctdb_client_pnn(ctdb->client));
2230 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2231 int argc, const char **argv)
2233 char *t, *lvs_helper = NULL;
2239 t = getenv("CTDB_LVS_HELPER");
2241 lvs_helper = talloc_strdup(mem_ctx, t);
2243 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2244 CTDB_HELPER_BINDIR);
2247 if (lvs_helper == NULL) {
2248 fprintf(stderr, "Unable to set LVS helper\n");
2252 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2255 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2256 int argc, const char **argv)
2266 found = debug_level_parse(argv[0], &log_level);
2269 "Invalid debug level '%s'. Valid levels are:\n",
2271 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2275 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2276 ctdb->cmd_pnn, TIMEOUT(), log_level);
2284 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2285 int argc, const char **argv)
2288 const char *log_str;
2295 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2296 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2301 log_str = debug_level_to_string(loglevel);
2302 printf("%s\n", log_str);
2307 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2308 int argc, const char **argv)
2310 const char *db_name;
2311 uint8_t db_flags = 0;
2314 if (argc < 1 || argc > 2) {
2320 if (strcmp(argv[1], "persistent") == 0) {
2321 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2322 } else if (strcmp(argv[1], "readonly") == 0) {
2323 db_flags = CTDB_DB_FLAGS_READONLY;
2324 } else if (strcmp(argv[1], "sticky") == 0) {
2325 db_flags = CTDB_DB_FLAGS_STICKY;
2326 } else if (strcmp(argv[1], "replicated") == 0) {
2327 db_flags = CTDB_DB_FLAGS_REPLICATED;
2333 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2342 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2343 int argc, const char **argv)
2345 const char *db_name;
2348 struct ctdb_node_map *nodemap;
2356 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2357 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2362 if (recmode == CTDB_RECOVERY_ACTIVE) {
2363 fprintf(stderr, "Database cannot be detached"
2364 " when recovery is active\n");
2368 nodemap = get_nodemap(ctdb, false);
2369 if (nodemap == NULL) {
2373 for (i=0; i<nodemap->num; i++) {
2376 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2379 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2382 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2383 fprintf(stderr, "Database cannot be detached on"
2384 " inactive (stopped or banned) node %u\n",
2385 nodemap->node[i].pnn);
2389 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2390 nodemap->node[i].pnn, TIMEOUT(),
2391 "AllowClientDBAttach", &value);
2394 "Unable to get tunable AllowClientDBAttach"
2395 " from node %u\n", nodemap->node[i].pnn);
2401 "Database access is still active on node %u."
2402 " Set AllowclientDBAttach=0 on all nodes.\n",
2403 nodemap->node[i].pnn);
2409 for (i=0; i<argc; i++) {
2410 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2416 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2418 "Only volatile databases can be detached\n");
2422 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2424 fprintf(stderr, "Database %s detach failed\n", db_name);
2432 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2433 int argc, const char **argv)
2435 const char *mem_str;
2439 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2440 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2445 n = write(1, mem_str, strlen(mem_str)+1);
2446 if (n < 0 || n != strlen(mem_str)+1) {
2447 fprintf(stderr, "Failed to write talloc summary\n");
2454 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2456 bool *done = (bool *)private_data;
2459 n = write(1, data.dptr, data.dsize);
2460 if (n < 0 || n != data.dsize) {
2461 fprintf(stderr, "Failed to write talloc summary\n");
2467 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2468 int argc, const char **argv)
2470 struct ctdb_srvid_message msg = { 0 };
2474 msg.pnn = ctdb->pnn;
2475 msg.srvid = next_srvid(ctdb);
2477 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2478 msg.srvid, dump_memory, &done);
2483 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2484 ctdb->cmd_pnn, &msg);
2489 ctdb_client_wait(ctdb->ev, &done);
2493 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2494 int argc, const char **argv)
2499 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2500 ctdb->cmd_pnn, TIMEOUT(), &pid);
2505 printf("%u\n", pid);
2509 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2510 const char *desc, uint32_t flag, bool set_flag)
2512 struct ctdb_node_map *nodemap;
2515 nodemap = get_nodemap(ctdb, false);
2516 if (nodemap == NULL) {
2520 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2521 if (set_flag == flag_is_set) {
2523 fprintf(stderr, "Node %u is already %s\n",
2524 ctdb->cmd_pnn, desc);
2526 fprintf(stderr, "Node %u is not %s\n",
2527 ctdb->cmd_pnn, desc);
2535 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2536 uint32_t flag, bool set_flag)
2538 struct ctdb_node_map *nodemap;
2542 nodemap = get_nodemap(ctdb, true);
2543 if (nodemap == NULL) {
2545 "Failed to get nodemap, trying again\n");
2550 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2551 if (flag_is_set == set_flag) {
2559 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2560 struct ctdb_client_context *client,
2561 uint32_t destnode, struct timeval timeout,
2562 uint32_t set, uint32_t clear)
2564 struct ctdb_node_map *nodemap;
2565 struct ctdb_node_flag_change flag_change;
2566 struct ctdb_req_control request;
2570 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2571 tevent_timeval_zero(), &nodemap);
2576 flag_change.pnn = destnode;
2577 flag_change.old_flags = nodemap->node[destnode].flags;
2578 flag_change.new_flags = flag_change.old_flags | set;
2579 flag_change.new_flags &= ~clear;
2581 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2586 ctdb_req_control_modify_flags(&request, &flag_change);
2587 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2588 tevent_timeval_zero(), &request,
2593 struct ipreallocate_state {
2598 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2601 struct ipreallocate_state *state =
2602 (struct ipreallocate_state *)private_data;
2604 if (data.dsize != sizeof(int)) {
2609 state->status = *(int *)data.dptr;
2613 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2615 struct ctdb_srvid_message msg = { 0 };
2616 struct ipreallocate_state state;
2619 msg.pnn = ctdb->pnn;
2620 msg.srvid = next_srvid(ctdb);
2623 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2625 ipreallocate_handler, &state);
2631 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2633 CTDB_BROADCAST_CONNECTED,
2639 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2645 if (state.status >= 0) {
2654 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2659 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2660 int argc, const char **argv)
2668 ret = check_flags(mem_ctx, ctdb, "disabled",
2669 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2674 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2675 ctdb->cmd_pnn, TIMEOUT(),
2676 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2679 "Failed to set DISABLED flag on node %u\n",
2684 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2685 return ipreallocate(mem_ctx, ctdb);
2688 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2689 int argc, const char **argv)
2697 ret = check_flags(mem_ctx, ctdb, "disabled",
2698 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2703 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2704 ctdb->cmd_pnn, TIMEOUT(),
2705 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2707 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2712 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2713 return ipreallocate(mem_ctx, ctdb);
2716 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2717 int argc, const char **argv)
2725 ret = check_flags(mem_ctx, ctdb, "stopped",
2726 NODE_FLAGS_STOPPED, true);
2731 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2732 ctdb->cmd_pnn, TIMEOUT());
2734 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2738 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2739 return ipreallocate(mem_ctx, ctdb);
2742 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2743 int argc, const char **argv)
2751 ret = check_flags(mem_ctx, ctdb, "stopped",
2752 NODE_FLAGS_STOPPED, false);
2757 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2758 ctdb->cmd_pnn, TIMEOUT());
2760 fprintf(stderr, "Failed to continue stopped node %u\n",
2765 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2766 return ipreallocate(mem_ctx, ctdb);
2769 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2770 int argc, const char **argv)
2772 struct ctdb_ban_state ban_state;
2779 ret = check_flags(mem_ctx, ctdb, "banned",
2780 NODE_FLAGS_BANNED, true);
2785 ban_state.pnn = ctdb->cmd_pnn;
2786 ban_state.time = strtoul(argv[0], NULL, 0);
2788 if (ban_state.time == 0) {
2789 fprintf(stderr, "Ban time cannot be zero\n");
2793 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2794 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2796 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2800 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2801 return ipreallocate(mem_ctx, ctdb);
2805 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2806 int argc, const char **argv)
2808 struct ctdb_ban_state ban_state;
2815 ret = check_flags(mem_ctx, ctdb, "banned",
2816 NODE_FLAGS_BANNED, false);
2821 ban_state.pnn = ctdb->cmd_pnn;
2824 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2825 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2827 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2831 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2832 return ipreallocate(mem_ctx, ctdb);
2836 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2837 int argc, const char **argv)
2845 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2846 ctdb->cmd_pnn, TIMEOUT());
2848 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2855 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2856 uint32_t *generation)
2860 struct ctdb_vnn_map *vnnmap;
2864 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2865 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2867 fprintf(stderr, "Failed to find recovery master\n");
2871 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2872 recmaster, TIMEOUT(), &recmode);
2874 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2879 if (recmode == CTDB_RECOVERY_ACTIVE) {
2884 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2885 recmaster, TIMEOUT(), &vnnmap);
2887 fprintf(stderr, "Failed to get generation from node %u\n",
2892 if (vnnmap->generation == INVALID_GENERATION) {
2893 talloc_free(vnnmap);
2898 *generation = vnnmap->generation;
2899 talloc_free(vnnmap);
2904 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2905 int argc, const char **argv)
2907 uint32_t generation, next_generation;
2914 ret = get_generation(mem_ctx, ctdb, &generation);
2919 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2920 ctdb->cmd_pnn, TIMEOUT(),
2921 CTDB_RECOVERY_ACTIVE);
2923 fprintf(stderr, "Failed to set recovery mode active\n");
2928 ret = get_generation(mem_ctx, ctdb, &next_generation);
2931 "Failed to confirm end of recovery\n");
2935 if (next_generation != generation) {
2945 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2946 int argc, const char **argv)
2949 usage("ipreallocate");
2952 return ipreallocate(mem_ctx, ctdb);
2955 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2956 struct ctdb_context *ctdb,
2957 int argc, const char **argv)
2963 usage("isnotrecmaster");
2966 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2967 ctdb->pnn, TIMEOUT(), &recmaster);
2969 fprintf(stderr, "Failed to get recmaster\n");
2973 if (recmaster != ctdb->pnn) {
2974 printf("this node is not the recmaster\n");
2978 printf("this node is the recmaster\n");
2982 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2983 int argc, const char **argv)
2985 struct ctdb_addr_info addr_info;
2992 ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
2994 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
2997 addr_info.iface = argv[1];
2999 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3000 ctdb->cmd_pnn, TIMEOUT(),
3003 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3011 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3012 int argc, const char **argv)
3014 ctdb_sock_addr src, dst;
3017 if (argc != 0 && argc != 2) {
3022 struct ctdb_connection_list *clist;
3025 /* Client first but the src/dst logic is confused */
3026 ret = ctdb_connection_list_read(mem_ctx, false, &clist);
3032 for (i = 0; i < clist->num; i++) {
3033 ret = ctdb_sys_send_tcp(&clist->conn[i].src,
3034 &clist->conn[i].dst,
3043 if (num_failed > 0) {
3044 fprintf(stderr, "Failed to send %d tickles\n",
3053 ret = ctdb_sock_addr_from_string(argv[0], &src, true);
3055 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3059 ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
3061 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3065 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3067 fprintf(stderr, "Failed to send tickle ack\n");
3074 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3075 int argc, const char **argv)
3077 ctdb_sock_addr addr;
3078 struct ctdb_tickle_list *tickles;
3082 if (argc < 1 || argc > 2) {
3083 usage("gettickles");
3087 port = strtoul(argv[1], NULL, 10);
3090 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3092 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3095 ctdb_sock_addr_set_port(&addr, port);
3097 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3098 ctdb->cmd_pnn, TIMEOUT(), &addr,
3101 fprintf(stderr, "Failed to get list of connections\n");
3105 if (options.machinereadable) {
3106 printf("%s%s%s%s%s%s%s%s%s\n",
3108 "Source IP", options.sep,
3109 "Port", options.sep,
3110 "Destiation IP", options.sep,
3111 "Port", options.sep);
3112 for (i=0; i<tickles->num; i++) {
3113 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3114 ctdb_sock_addr_to_string(
3115 mem_ctx, &tickles->conn[i].src, false),
3117 ntohs(tickles->conn[i].src.ip.sin_port),
3119 ctdb_sock_addr_to_string(
3120 mem_ctx, &tickles->conn[i].dst, false),
3122 ntohs(tickles->conn[i].dst.ip.sin_port),
3126 printf("Connections for IP: %s\n",
3127 ctdb_sock_addr_to_string(mem_ctx,
3128 &tickles->addr, false));
3129 printf("Num connections: %u\n", tickles->num);
3130 for (i=0; i<tickles->num; i++) {
3131 printf("SRC: %s DST: %s\n",
3132 ctdb_sock_addr_to_string(
3133 mem_ctx, &tickles->conn[i].src, true),
3134 ctdb_sock_addr_to_string(
3135 mem_ctx, &tickles->conn[i].dst, true));
3139 talloc_free(tickles);
3143 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3144 struct ctdb_connection *conn);
3146 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3148 struct process_clist_state {
3149 struct ctdb_connection_list *clist;
3151 int num_failed, num_total;
3152 clist_reply_func reply_func;
3155 static void process_clist_done(struct tevent_req *subreq);
3157 static struct tevent_req *process_clist_send(
3158 TALLOC_CTX *mem_ctx,
3159 struct ctdb_context *ctdb,
3160 struct ctdb_connection_list *clist,
3161 clist_request_func request_func,
3162 clist_reply_func reply_func)
3164 struct tevent_req *req, *subreq;
3165 struct process_clist_state *state;
3166 struct ctdb_req_control request;
3169 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3174 state->clist = clist;
3175 state->reply_func = reply_func;
3177 for (i = 0; i < clist->num; i++) {
3178 request_func(&request, &clist->conn[i]);
3179 subreq = ctdb_client_control_send(state, ctdb->ev,
3180 ctdb->client, ctdb->cmd_pnn,
3181 TIMEOUT(), &request);
3182 if (tevent_req_nomem(subreq, req)) {
3183 return tevent_req_post(req, ctdb->ev);
3185 tevent_req_set_callback(subreq, process_clist_done, req);
3191 static void process_clist_done(struct tevent_req *subreq)
3193 struct tevent_req *req = tevent_req_callback_data(
3194 subreq, struct tevent_req);
3195 struct process_clist_state *state = tevent_req_data(
3196 req, struct process_clist_state);
3197 struct ctdb_reply_control *reply;
3201 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3202 TALLOC_FREE(subreq);
3204 state->num_failed += 1;
3208 ret = state->reply_func(reply);
3210 state->num_failed += 1;
3215 state->num_total += 1;
3216 if (state->num_total == state->clist->num) {
3217 tevent_req_done(req);
3221 static int process_clist_recv(struct tevent_req *req)
3223 struct process_clist_state *state = tevent_req_data(
3224 req, struct process_clist_state);
3226 return state->num_failed;
3229 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3230 int argc, const char **argv)
3232 struct ctdb_connection conn;
3235 if (argc != 0 && argc != 2) {
3240 struct ctdb_connection_list *clist;
3241 struct tevent_req *req;
3243 /* Client first but the src/dst logic is confused */
3244 ret = ctdb_connection_list_read(mem_ctx, false, &clist);
3248 if (clist->num == 0) {
3252 req = process_clist_send(mem_ctx, ctdb, clist,
3253 ctdb_req_control_tcp_add_delayed_update,
3254 ctdb_reply_control_tcp_add_delayed_update);
3260 tevent_req_poll(req, ctdb->ev);
3263 ret = process_clist_recv(req);
3265 fprintf(stderr, "Failed to add %d tickles\n", ret);
3272 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3274 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3277 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3279 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3283 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3284 ctdb->client, ctdb->cmd_pnn,
3287 fprintf(stderr, "Failed to register connection\n");
3294 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3295 int argc, const char **argv)
3297 struct ctdb_connection conn;
3300 if (argc != 0 && argc != 2) {
3305 struct ctdb_connection_list *clist;
3306 struct tevent_req *req;
3308 /* Client first but the src/dst logic is confused */
3309 ret = ctdb_connection_list_read(mem_ctx, false, &clist);
3313 if (clist->num == 0) {
3317 req = process_clist_send(mem_ctx, ctdb, clist,
3318 ctdb_req_control_tcp_remove,
3319 ctdb_reply_control_tcp_remove);
3325 tevent_req_poll(req, ctdb->ev);
3328 ret = process_clist_recv(req);
3330 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3337 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3339 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3342 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3344 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3348 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3349 ctdb->cmd_pnn, TIMEOUT(), &conn);
3351 fprintf(stderr, "Failed to unregister connection\n");
3358 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3359 int argc, const char **argv)
3361 struct ctdb_node_map *nodemap;
3368 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3369 if (nodemap == NULL) {
3373 for (i=0; i<nodemap->num; i++) {
3374 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3378 if (options.machinereadable) {
3379 printf("%s%u%s%s%s\n", options.sep,
3380 nodemap->node[i].pnn, options.sep,
3381 ctdb_sock_addr_to_string(
3382 mem_ctx, &nodemap->node[i].addr, false),
3386 ctdb_sock_addr_to_string(
3387 mem_ctx, &nodemap->node[i].addr, false));
3394 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3395 struct ctdb_node_map *nodemap2)
3399 if (nodemap1->num != nodemap2->num) {
3403 for (i=0; i<nodemap1->num; i++) {
3404 struct ctdb_node_and_flags *n1, *n2;
3406 n1 = &nodemap1->node[i];
3407 n2 = &nodemap2->node[i];
3409 if ((n1->pnn != n2->pnn) ||
3410 (n1->flags != n2->flags) ||
3411 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3419 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3420 struct ctdb_node_map *nm,
3421 struct ctdb_node_map *fnm,
3425 bool check_failed = false;
3429 for (i=0; i<nm->num; i++) {
3430 if (i >= fnm->num) {
3432 "Node %u (%s) missing from nodes file\n",
3434 ctdb_sock_addr_to_string(
3435 mem_ctx, &nm->node[i].addr, false));
3436 check_failed = true;
3439 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3440 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3441 /* Node remains deleted */
3445 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3446 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3447 /* Node not newly nor previously deleted */
3448 if (! ctdb_same_ip(&nm->node[i].addr,
3449 &fnm->node[i].addr)) {
3451 "Node %u has changed IP address"
3452 " (was %s, now %s)\n",
3454 ctdb_sock_addr_to_string(
3456 &nm->node[i].addr, false),
3457 ctdb_sock_addr_to_string(
3459 &fnm->node[i].addr, false));
3460 check_failed = true;
3462 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3464 "WARNING: Node %u is disconnected."
3465 " You MUST fix this node manually!\n",
3472 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3473 /* Node is being deleted */
3474 printf("Node %u is DELETED\n", nm->node[i].pnn);
3476 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3478 "ERROR: Node %u is still connected\n",
3480 check_failed = true;
3485 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3486 /* Node was previously deleted */
3487 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3494 "ERROR: Nodes will not be reloaded due to previous error\n");
3498 /* Leftover nodes in file are NEW */
3499 for (; i < fnm->num; i++) {
3500 printf("Node %u is NEW\n", fnm->node[i].pnn);
3507 struct disable_recoveries_state {
3515 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3518 struct disable_recoveries_state *state =
3519 (struct disable_recoveries_state *)private_data;
3522 if (data.dsize != sizeof(int)) {
3527 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3528 ret = *(int *)data.dptr;
3530 state->status = ret;
3534 for (i=0; i<state->node_count; i++) {
3535 if (state->pnn_list[i] == ret) {
3536 state->reply[i] = true;
3542 for (i=0; i<state->node_count; i++) {
3543 if (! state->reply[i]) {
3544 state->done = false;
3550 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3551 uint32_t timeout, uint32_t *pnn_list, int count)
3553 struct ctdb_disable_message disable = { 0 };
3554 struct disable_recoveries_state state;
3557 disable.pnn = ctdb->pnn;
3558 disable.srvid = next_srvid(ctdb);
3559 disable.timeout = timeout;
3561 state.pnn_list = pnn_list;
3562 state.node_count = count;
3565 state.reply = talloc_zero_array(mem_ctx, bool, count);
3566 if (state.reply == NULL) {
3570 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3572 disable_recoveries_handler,
3578 for (i=0; i<count; i++) {
3579 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3588 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3590 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3592 ret = (state.status >= 0 ? 0 : 1);
3596 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3597 disable.srvid, &state);
3601 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3602 int argc, const char **argv)
3604 struct ctdb_node_map *nodemap = NULL;
3605 struct ctdb_node_map *file_nodemap;
3606 struct ctdb_node_map *remote_nodemap;
3607 struct ctdb_req_control request;
3608 struct ctdb_reply_control **reply;
3614 nodemap = get_nodemap(ctdb, false);
3615 if (nodemap == NULL) {
3619 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3620 if (file_nodemap == NULL) {
3624 for (i=0; i<nodemap->num; i++) {
3625 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3629 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3630 nodemap->node[i].pnn, TIMEOUT(),
3634 "ERROR: Failed to get nodes file from node %u\n",
3635 nodemap->node[i].pnn);
3639 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3641 "ERROR: Nodes file on node %u differs"
3642 " from current node (%u)\n",
3643 nodemap->node[i].pnn, ctdb->pnn);
3648 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3654 fprintf(stderr, "No change in nodes file,"
3655 " skipping unnecessary reload\n");
3659 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3660 mem_ctx, &pnn_list);
3662 fprintf(stderr, "Memory allocation error\n");
3666 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3669 fprintf(stderr, "Failed to disable recoveries\n");
3673 ctdb_req_control_reload_nodes_file(&request);
3674 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3675 pnn_list, count, TIMEOUT(),
3676 &request, NULL, &reply);
3678 bool failed = false;
3680 for (i=0; i<count; i++) {
3681 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3684 "Node %u failed to reload nodes\n",
3691 "You MUST fix failed nodes manually!\n");
3695 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3697 fprintf(stderr, "Failed to enable recoveries\n");
3704 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3705 ctdb_sock_addr *addr, uint32_t pnn)
3707 struct ctdb_public_ip_list *pubip_list;
3708 struct ctdb_public_ip pubip;
3709 struct ctdb_node_map *nodemap;
3710 struct ctdb_req_control request;
3714 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3715 CTDB_BROADCAST_CONNECTED,
3716 2*options.timelimit);
3718 fprintf(stderr, "Failed to disable IP check\n");
3722 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3723 pnn, TIMEOUT(), false, &pubip_list);
3725 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3730 for (i=0; i<pubip_list->num; i++) {
3731 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3736 if (i == pubip_list->num) {
3737 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3738 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3742 nodemap = get_nodemap(ctdb, false);
3743 if (nodemap == NULL) {
3747 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3749 fprintf(stderr, "Memory allocation error\n");
3755 ctdb_req_control_release_ip(&request, &pubip);
3757 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3758 pnn_list, count, TIMEOUT(),
3759 &request, NULL, NULL);
3761 fprintf(stderr, "Failed to release IP on nodes\n");
3765 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3766 pnn, TIMEOUT(), &pubip);
3768 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3775 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3776 int argc, const char **argv)
3778 ctdb_sock_addr addr;
3780 int ret, retries = 0;
3786 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3788 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3792 pnn = strtoul(argv[1], NULL, 10);
3793 if (pnn == CTDB_UNKNOWN_PNN) {
3794 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3798 while (retries < 5) {
3799 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3809 fprintf(stderr, "Failed to move IP %s to node %u\n",
3817 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3822 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3823 CTDB_BROADCAST_CONNECTED, pnn);
3826 "Failed to ask recovery master to distribute IPs\n");
3833 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3834 int argc, const char **argv)
3836 ctdb_sock_addr addr;
3837 struct ctdb_public_ip_list *pubip_list;
3838 struct ctdb_addr_info addr_info;
3840 int ret, i, retries = 0;
3846 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3847 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3851 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3852 ctdb->cmd_pnn, TIMEOUT(),
3853 false, &pubip_list);
3855 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3860 for (i=0; i<pubip_list->num; i++) {
3861 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3862 fprintf(stderr, "Node already knows about IP %s\n",
3863 ctdb_sock_addr_to_string(mem_ctx,
3869 addr_info.addr = addr;
3870 addr_info.mask = mask;
3871 addr_info.iface = argv[1];
3873 while (retries < 5) {
3874 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3875 ctdb->cmd_pnn, TIMEOUT(),
3886 fprintf(stderr, "Failed to add public IP to node %u."
3887 " Giving up\n", ctdb->cmd_pnn);
3891 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3899 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3900 int argc, const char **argv)
3902 ctdb_sock_addr addr;
3903 struct ctdb_public_ip_list *pubip_list;
3904 struct ctdb_addr_info addr_info;
3911 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3913 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3917 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3918 ctdb->cmd_pnn, TIMEOUT(),
3919 false, &pubip_list);
3921 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3926 for (i=0; i<pubip_list->num; i++) {
3927 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3932 if (i == pubip_list->num) {
3933 fprintf(stderr, "Node does not know about IP address %s\n",
3934 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
3938 addr_info.addr = addr;
3940 addr_info.iface = NULL;
3942 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3943 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3945 fprintf(stderr, "Failed to delete public IP from node %u\n",
3953 #define DB_VERSION 3
3954 #define MAX_DB_NAME 64
3955 #define MAX_REC_BUFFER_SIZE (100*1000)
3958 unsigned long version;
3960 unsigned long flags;
3963 char name[MAX_DB_NAME];
3966 struct backup_state {
3967 TALLOC_CTX *mem_ctx;
3968 struct ctdb_rec_buffer *recbuf;
3971 unsigned int nbuf, nrec;
3974 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
3975 TDB_DATA key, TDB_DATA data, void *private_data)
3977 struct backup_state *state = (struct backup_state *)private_data;
3981 if (state->recbuf == NULL) {
3982 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
3984 if (state->recbuf == NULL) {
3989 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
3995 len = ctdb_rec_buffer_len(state->recbuf);
3996 if (len < MAX_REC_BUFFER_SIZE) {
4000 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4002 fprintf(stderr, "Failed to write records to backup file\n");
4007 state->nrec += state->recbuf->count;
4008 TALLOC_FREE(state->recbuf);
4013 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4014 int argc, const char **argv)
4016 const char *db_name;
4017 struct ctdb_db_context *db;
4020 struct backup_state state;
4021 struct db_header db_hdr;
4028 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4032 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4035 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4039 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4042 fprintf(stderr, "Failed to open file %s for writing\n",
4047 /* Write empty header first */
4048 ZERO_STRUCT(db_hdr);
4049 ret = write(fd, &db_hdr, sizeof(struct db_header));
4053 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4057 state.mem_ctx = mem_ctx;
4058 state.recbuf = NULL;
4063 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4065 fprintf(stderr, "Failed to collect records from DB %s\n",
4071 if (state.recbuf != NULL) {
4072 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4075 "Failed to write records to backup file\n");
4081 state.nrec += state.recbuf->count;
4082 TALLOC_FREE(state.recbuf);
4085 db_hdr.version = DB_VERSION;
4086 db_hdr.timestamp = time(NULL);
4087 db_hdr.flags = db_flags;
4088 db_hdr.nbuf = state.nbuf;
4089 db_hdr.nrec = state.nrec;
4090 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4092 lseek(fd, 0, SEEK_SET);
4093 ret = write(fd, &db_hdr, sizeof(struct db_header));
4097 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4102 printf("Database backed up to %s\n", argv[1]);
4106 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4107 int argc, const char **argv)
4109 const char *db_name = NULL;
4110 struct ctdb_db_context *db;
4111 struct db_header db_hdr;
4112 struct ctdb_node_map *nodemap;
4113 struct ctdb_req_control request;
4114 struct ctdb_reply_control **reply;
4115 struct ctdb_transdb wipedb;
4116 struct ctdb_pulldb_ext pulldb;
4117 struct ctdb_rec_buffer *recbuf;
4118 uint32_t generation;
4126 if (argc < 1 || argc > 2) {
4130 fd = open(argv[0], O_RDONLY, 0600);
4133 fprintf(stderr, "Failed to open file %s for reading\n",
4142 n = read(fd, &db_hdr, sizeof(struct db_header));
4146 fprintf(stderr, "Failed to read db header from file %s\n",
4150 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4152 if (db_hdr.version != DB_VERSION) {
4154 "Wrong version of backup file, expected %u, got %lu\n",
4155 DB_VERSION, db_hdr.version);
4160 if (db_name == NULL) {
4161 db_name = db_hdr.name;
4164 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4165 localtime(&db_hdr.timestamp));
4166 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4168 db_flags = db_hdr.flags & 0xff;
4169 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4172 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4177 nodemap = get_nodemap(ctdb, false);
4178 if (nodemap == NULL) {
4179 fprintf(stderr, "Failed to get nodemap\n");
4184 ret = get_generation(mem_ctx, ctdb, &generation);
4186 fprintf(stderr, "Failed to get current generation\n");
4191 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4198 wipedb.db_id = ctdb_db_id(db);
4199 wipedb.tid = generation;
4201 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4202 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4203 ctdb->client, pnn_list, count,
4204 TIMEOUT(), &request, NULL, NULL);
4210 ctdb_req_control_db_transaction_start(&request, &wipedb);
4211 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4212 pnn_list, count, TIMEOUT(),
4213 &request, NULL, NULL);
4218 ctdb_req_control_wipe_database(&request, &wipedb);
4219 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4220 pnn_list, count, TIMEOUT(),
4221 &request, NULL, NULL);
4226 pulldb.db_id = ctdb_db_id(db);
4228 pulldb.srvid = SRVID_CTDB_PUSHDB;
4230 ctdb_req_control_db_push_start(&request, &pulldb);
4231 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4232 pnn_list, count, TIMEOUT(),
4233 &request, NULL, NULL);
4238 for (i=0; i<db_hdr.nbuf; i++) {
4239 struct ctdb_req_message message;
4243 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4248 data.dsize = ctdb_rec_buffer_len(recbuf);
4249 data.dptr = talloc_size(mem_ctx, data.dsize);
4250 if (data.dptr == NULL) {
4254 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4256 message.srvid = pulldb.srvid;
4257 message.data.data = data;
4259 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4267 talloc_free(recbuf);
4268 talloc_free(data.dptr);
4271 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4272 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4273 pnn_list, count, TIMEOUT(),
4274 &request, NULL, &reply);
4279 for (i=0; i<count; i++) {
4280 uint32_t num_records;
4282 ret = ctdb_reply_control_db_push_confirm(reply[i],
4285 fprintf(stderr, "Invalid response from node %u\n",
4290 if (num_records != db_hdr.nrec) {
4291 fprintf(stderr, "Node %u received %u of %lu records\n",
4292 pnn_list[i], num_records, db_hdr.nrec);
4297 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4298 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4299 pnn_list, count, TIMEOUT(),
4300 &request, NULL, NULL);
4305 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4306 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4307 pnn_list, count, TIMEOUT(),
4308 &request, NULL, NULL);
4313 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4314 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4315 ctdb->client, pnn_list, count,
4316 TIMEOUT(), &request, NULL, NULL);
4321 printf("Database %s restored\n", db_name);
4328 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4329 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4333 struct dumpdbbackup_state {
4334 ctdb_rec_parser_func_t parser;
4335 struct dump_record_state sub_state;
4338 static int dumpdbbackup_handler(uint32_t reqid,
4339 struct ctdb_ltdb_header *header,
4340 TDB_DATA key, TDB_DATA data,
4343 struct dumpdbbackup_state *state =
4344 (struct dumpdbbackup_state *)private_data;
4345 struct ctdb_ltdb_header hdr;
4348 ret = ctdb_ltdb_header_extract(&data, &hdr);
4353 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4356 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4357 int argc, const char **argv)
4359 struct db_header db_hdr;
4361 struct dumpdbbackup_state state;
4366 usage("dumpbackup");
4369 fd = open(argv[0], O_RDONLY, 0600);
4372 fprintf(stderr, "Failed to open file %s for reading\n",
4377 n = read(fd, &db_hdr, sizeof(struct db_header));
4381 fprintf(stderr, "Failed to read db header from file %s\n",
4385 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4387 if (db_hdr.version != DB_VERSION) {
4389 "Wrong version of backup file, expected %u, got %lu\n",
4390 DB_VERSION, db_hdr.version);
4395 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4396 localtime(&db_hdr.timestamp));
4397 printf("Dumping database %s from backup @ %s\n",
4398 db_hdr.name, timebuf);
4400 state.parser = dump_record;
4401 state.sub_state.count = 0;
4403 for (i=0; i<db_hdr.nbuf; i++) {
4404 struct ctdb_rec_buffer *recbuf;
4406 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4408 fprintf(stderr, "Failed to read records\n");
4413 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4416 fprintf(stderr, "Failed to dump records\n");
4423 printf("Dumped %u record(s)\n", state.sub_state.count);
4427 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4428 int argc, const char **argv)
4430 const char *db_name;
4431 struct ctdb_db_context *db;
4434 struct ctdb_node_map *nodemap;
4435 struct ctdb_req_control request;
4436 struct ctdb_transdb wipedb;
4437 uint32_t generation;
4445 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4449 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4452 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4456 nodemap = get_nodemap(ctdb, false);
4457 if (nodemap == NULL) {
4458 fprintf(stderr, "Failed to get nodemap\n");
4462 ret = get_generation(mem_ctx, ctdb, &generation);
4464 fprintf(stderr, "Failed to get current generation\n");
4468 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4474 ctdb_req_control_db_freeze(&request, db_id);
4475 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4476 ctdb->client, pnn_list, count,
4477 TIMEOUT(), &request, NULL, NULL);
4482 wipedb.db_id = db_id;
4483 wipedb.tid = generation;
4485 ctdb_req_control_db_transaction_start(&request, &wipedb);
4486 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4487 pnn_list, count, TIMEOUT(),
4488 &request, NULL, NULL);
4493 ctdb_req_control_wipe_database(&request, &wipedb);
4494 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4495 pnn_list, count, TIMEOUT(),
4496 &request, NULL, NULL);
4501 ctdb_req_control_db_set_healthy(&request, db_id);
4502 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4503 pnn_list, count, TIMEOUT(),
4504 &request, NULL, NULL);
4509 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4510 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4511 pnn_list, count, TIMEOUT(),
4512 &request, NULL, NULL);
4517 ctdb_req_control_db_thaw(&request, db_id);
4518 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4519 ctdb->client, pnn_list, count,
4520 TIMEOUT(), &request, NULL, NULL);
4525 printf("Database %s wiped\n", db_name);
4530 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4531 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4535 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4536 int argc, const char **argv)
4541 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4542 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4547 printf("%u\n", recmaster);
4551 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4552 int argc, const char **argv)
4554 char *t, *event_helper = NULL;
4555 char *eventd_socket = NULL;
4556 const char **new_argv;
4559 t = getenv("CTDB_EVENT_HELPER");
4561 event_helper = talloc_strdup(mem_ctx, t);
4563 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb_event",
4564 CTDB_HELPER_BINDIR);
4567 if (event_helper == NULL) {
4568 fprintf(stderr, "Unable to set event daemon helper\n");
4572 t = getenv("CTDB_SOCKET");
4574 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4577 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4581 if (eventd_socket == NULL) {
4582 fprintf(stderr, "Unable to set event daemon socket\n");
4586 new_argv = talloc_array(mem_ctx, const char *, argc + 1);
4587 if (new_argv == NULL) {
4588 fprintf(stderr, "Memory allocation error\n");
4592 new_argv[0] = eventd_socket;
4593 for (i=0; i<argc; i++) {
4594 new_argv[i+1] = argv[i];
4597 return run_helper(mem_ctx, "event daemon helper", event_helper,
4601 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4602 int argc, const char **argv)
4604 const char *new_argv[3];
4607 usage("scriptstatus");
4610 new_argv[0] = "status";
4611 new_argv[1] = (argc == 0) ? "monitor" : argv[0];
4614 (void) control_event(mem_ctx, ctdb, 2, new_argv);
4618 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4619 int argc, const char **argv)
4621 char *t, *natgw_helper = NULL;
4627 t = getenv("CTDB_NATGW_HELPER");
4629 natgw_helper = talloc_strdup(mem_ctx, t);
4631 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4632 CTDB_HELPER_BINDIR);
4635 if (natgw_helper == NULL) {
4636 fprintf(stderr, "Unable to set NAT gateway helper\n");
4640 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4645 * Find the PNN of the current node
4646 * discover the pnn by loading the nodes file and try to bind
4647 * to all addresses one at a time until the ip address is found.
4649 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4651 struct ctdb_node_map *nodemap;
4654 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4655 if (nodemap == NULL) {
4659 for (i=0; i<nodemap->num; i++) {
4660 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4663 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4665 *pnn = nodemap->node[i].pnn;
4667 talloc_free(nodemap);
4672 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4673 talloc_free(nodemap);
4677 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4678 int argc, const char **argv)
4680 const char *reclock;
4684 usage("getreclock");
4687 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4688 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4693 if (reclock != NULL) {
4694 printf("%s\n", reclock);
4700 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4701 struct ctdb_context *ctdb,
4702 int argc, const char **argv)
4704 uint32_t lmasterrole = 0;
4708 usage("setlmasterrole");
4711 if (strcmp(argv[0], "on") == 0) {
4713 } else if (strcmp(argv[0], "off") == 0) {
4716 usage("setlmasterrole");
4719 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4720 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4728 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4729 struct ctdb_context *ctdb,
4730 int argc, const char **argv)
4732 uint32_t recmasterrole = 0;
4736 usage("setrecmasterrole");
4739 if (strcmp(argv[0], "on") == 0) {
4741 } else if (strcmp(argv[0], "off") == 0) {
4744 usage("setrecmasterrole");
4747 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4748 ctdb->cmd_pnn, TIMEOUT(),
4757 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4758 struct ctdb_context *ctdb,
4759 int argc, const char **argv)
4766 usage("setdbreadonly");
4769 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4773 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4774 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4778 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4779 ctdb->cmd_pnn, TIMEOUT(), db_id);
4787 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4788 int argc, const char **argv)
4795 usage("setdbsticky");
4798 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4802 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4803 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4807 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4808 ctdb->cmd_pnn, TIMEOUT(), db_id);
4816 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4817 int argc, const char **argv)
4819 const char *db_name;
4820 struct ctdb_db_context *db;
4821 struct ctdb_transaction_handle *h;
4826 if (argc < 2 || argc > 3) {
4830 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4835 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4836 fprintf(stderr, "Transactions not supported on DB %s\n",
4841 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4844 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4848 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4850 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4854 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4855 TIMEOUT(), db, true, &h);
4857 fprintf(stderr, "Failed to start transaction on db %s\n",
4862 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4864 fprintf(stderr, "Failed to read record for key %s\n",
4866 ctdb_transaction_cancel(h);
4870 printf("%.*s\n", (int)data.dsize, data.dptr);
4872 ctdb_transaction_cancel(h);
4876 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4877 int argc, const char **argv)
4879 const char *db_name;
4880 struct ctdb_db_context *db;
4881 struct ctdb_transaction_handle *h;
4890 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4895 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4896 fprintf(stderr, "Transactions not supported on DB %s\n",
4901 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4904 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4908 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4910 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4914 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4916 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4920 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4921 TIMEOUT(), db, false, &h);
4923 fprintf(stderr, "Failed to start transaction on db %s\n",
4928 ret = ctdb_transaction_store_record(h, key, data);
4930 fprintf(stderr, "Failed to store record for key %s\n",
4932 ctdb_transaction_cancel(h);
4936 ret = ctdb_transaction_commit(h);
4938 fprintf(stderr, "Failed to commit transaction on db %s\n",
4940 ctdb_transaction_cancel(h);
4947 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4948 int argc, const char **argv)
4950 const char *db_name;
4951 struct ctdb_db_context *db;
4952 struct ctdb_transaction_handle *h;
4961 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4966 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4967 fprintf(stderr, "Transactions not supported on DB %s\n",
4972 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4975 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4979 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4981 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4985 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4986 TIMEOUT(), db, false, &h);
4988 fprintf(stderr, "Failed to start transaction on db %s\n",
4993 ret = ctdb_transaction_delete_record(h, key);
4995 fprintf(stderr, "Failed to delete record for key %s\n",
4997 ctdb_transaction_cancel(h);
5001 ret = ctdb_transaction_commit(h);
5003 fprintf(stderr, "Failed to commit transaction on db %s\n",
5005 ctdb_transaction_cancel(h);
5012 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5020 /* Skip whitespace */
5021 n = strspn(*ptr, " \t");
5025 /* Quoted ASCII string - no wide characters! */
5027 n = strcspn(t, "\"");
5030 ret = str_to_data(t, n, mem_ctx, data);
5037 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5041 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5048 #define MAX_LINE_SIZE 1024
5050 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5051 TDB_DATA *key, TDB_DATA *value)
5053 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5057 ptr = fgets(line, MAX_LINE_SIZE, file);
5063 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5064 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5065 /* Line Ignored but not EOF */
5071 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5073 /* Line Ignored but not EOF */
5074 talloc_free(key->dptr);
5082 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5083 int argc, const char **argv)
5085 const char *db_name;
5086 struct ctdb_db_context *db;
5087 struct ctdb_transaction_handle *h;
5090 TDB_DATA key, value;
5093 if (argc < 1 || argc > 2) {
5097 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5102 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5103 fprintf(stderr, "Transactions not supported on DB %s\n",
5109 file = fopen(argv[1], "r");
5111 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5118 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5121 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5125 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5126 TIMEOUT(), db, false, &h);
5128 fprintf(stderr, "Failed to start transaction on db %s\n",
5133 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5134 if (key.dsize != 0) {
5135 ret = ctdb_transaction_store_record(h, key, value);
5137 fprintf(stderr, "Failed to store record\n");
5138 ctdb_transaction_cancel(h);
5141 talloc_free(key.dptr);
5142 talloc_free(value.dptr);
5146 ret = ctdb_transaction_commit(h);
5148 fprintf(stderr, "Failed to commit transaction on db %s\n",
5150 ctdb_transaction_cancel(h);
5154 if (file != stdin) {
5160 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5161 int argc, const char **argv)
5163 struct tdb_context *tdb;
5165 struct ctdb_ltdb_header header;
5168 if (argc < 2 || argc > 3) {
5172 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5174 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5178 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5180 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5185 data = tdb_fetch(tdb, key);
5186 if (data.dptr == NULL) {
5187 fprintf(stderr, "No record for key %s\n", argv[1]);
5192 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5193 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5204 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5206 fprintf(stderr, "Failed to open output file %s\n",
5211 nwritten = sys_write(fd, data.dptr, data.dsize);
5212 if (nwritten != data.dsize) {
5213 fprintf(stderr, "Failed to write record to file\n");
5222 ret = ctdb_ltdb_header_extract(&data, &header);
5224 fprintf(stderr, "Failed to parse header from data\n");
5228 dump_ltdb_header(&header);
5229 dump_tdb_data("data", data);
5234 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5235 int argc, const char **argv)
5237 struct tdb_context *tdb;
5238 TDB_DATA key, data[2], value;
5239 struct ctdb_ltdb_header header;
5240 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5244 if (argc < 3 || argc > 5) {
5248 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5250 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5254 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5256 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5261 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5263 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5268 ZERO_STRUCT(header);
5271 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5274 header.dmaster = (uint32_t)atol(argv[4]);
5277 header.flags = (uint32_t)atol(argv[5]);
5280 ctdb_ltdb_header_push(&header, header_buf, &np);
5283 data[0].dptr = header_buf;
5285 data[1].dsize = value.dsize;
5286 data[1].dptr = value.dptr;
5288 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5290 fprintf(stderr, "Failed to write record %s to file %s\n",
5299 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5300 int argc, const char **argv)
5302 const char *db_name;
5303 struct ctdb_db_context *db;
5304 struct ctdb_record_handle *h;
5307 bool readonly = false;
5310 if (argc < 2 || argc > 3) {
5315 if (strcmp(argv[2], "readonly") == 0) {
5322 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5326 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5327 fprintf(stderr, "DB %s is not a volatile database\n",
5332 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5335 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5339 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5341 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5345 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5346 db, key, readonly, &h, NULL, &data);
5348 fprintf(stderr, "Failed to read record for key %s\n",
5351 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5352 (int)data.dsize, data.dptr);
5359 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5360 int argc, const char **argv)
5362 const char *db_name;
5363 struct ctdb_db_context *db;
5364 struct ctdb_record_handle *h;
5373 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5377 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5378 fprintf(stderr, "DB %s is not a volatile database\n",
5383 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5386 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5390 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5392 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5396 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5398 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5402 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5403 db, key, false, &h, NULL, NULL);
5405 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5409 ret = ctdb_store_record(h, data);
5411 fprintf(stderr, "Failed to store record for key %s\n",
5419 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5420 int argc, const char **argv)
5422 const char *db_name;
5423 struct ctdb_db_context *db;
5424 struct ctdb_record_handle *h;
5433 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5437 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5438 fprintf(stderr, "DB %s is not a volatile database\n",
5443 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5446 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5450 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5452 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5456 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5457 db, key, false, &h, NULL, &data);
5459 fprintf(stderr, "Failed to fetch record for key %s\n",
5464 ret = ctdb_delete_record(h);
5466 fprintf(stderr, "Failed to delete record for key %s\n",
5474 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5475 int argc, const char **argv)
5477 struct sockaddr_in sin;
5483 usage("chktcpport");
5486 port = atoi(argv[0]);
5488 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5490 fprintf(stderr, "Failed to open local socket\n");
5494 v = fcntl(s, F_GETFL, 0);
5495 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5496 fprintf(stderr, "Unable to set socket non-blocking\n");
5501 bzero(&sin, sizeof(sin));
5502 sin.sin_family = AF_INET;
5503 sin.sin_port = htons(port);
5504 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5507 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5514 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5515 int argc, const char **argv)
5518 const char *db_name;
5523 usage("getdbseqnum");
5526 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5530 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5531 ctdb->cmd_pnn, TIMEOUT(), db_id,
5534 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5539 printf("0x%"PRIx64"\n", seqnum);
5543 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5544 int argc, const char **argv)
5546 const char *nodestring = NULL;
5547 struct ctdb_node_map *nodemap;
5549 bool print_hdr = false;
5552 usage("nodestatus");
5556 nodestring = argv[0];
5557 if (strcmp(nodestring, "all") == 0) {
5562 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5566 if (options.machinereadable) {
5567 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5569 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5573 for (i=0; i<nodemap->num; i++) {
5574 ret |= nodemap->node[i].flags;
5583 } db_stats_fields[] = {
5584 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5585 DBSTATISTICS_FIELD(db_ro_delegations),
5586 DBSTATISTICS_FIELD(db_ro_revokes),
5587 DBSTATISTICS_FIELD(locks.num_calls),
5588 DBSTATISTICS_FIELD(locks.num_current),
5589 DBSTATISTICS_FIELD(locks.num_pending),
5590 DBSTATISTICS_FIELD(locks.num_failed),
5593 static void print_dbstatistics(const char *db_name,
5594 struct ctdb_db_statistics *s)
5597 const char *prefix = NULL;
5600 printf("DB Statistics %s\n", db_name);
5602 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5603 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5604 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5606 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5607 prefix = db_stats_fields[i].name;
5608 printf(" %*.*s\n", preflen-1, preflen-1,
5609 db_stats_fields[i].name);
5614 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5615 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5616 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5619 printf(" hop_count_buckets:");
5620 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5621 printf(" %d", s->hop_count_bucket[i]);
5625 printf(" lock_buckets:");
5626 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5627 printf(" %d", s->locks.buckets[i]);
5631 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5632 "locks_latency MIN/AVG/MAX",
5633 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5634 s->locks.latency.max, s->locks.latency.num);
5636 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5637 "vacuum_latency MIN/AVG/MAX",
5638 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5639 s->vacuum.latency.max, s->vacuum.latency.num);
5641 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5642 for (i=0; i<s->num_hot_keys; i++) {
5644 printf(" Count:%d Key:", s->hot_keys[i].count);
5645 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5646 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5652 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5653 int argc, const char **argv)
5656 const char *db_name;
5657 struct ctdb_db_statistics *dbstats;
5661 usage("dbstatistics");
5664 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5668 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5669 ctdb->cmd_pnn, TIMEOUT(), db_id,
5672 fprintf(stderr, "Failed to get statistics for DB %s\n",
5677 print_dbstatistics(db_name, dbstats);
5681 struct disable_takeover_runs_state {
5689 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5692 struct disable_takeover_runs_state *state =
5693 (struct disable_takeover_runs_state *)private_data;
5696 if (data.dsize != sizeof(int)) {
5701 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5702 ret = *(int *)data.dptr;
5704 state->status = ret;
5708 for (i=0; i<state->node_count; i++) {
5709 if (state->pnn_list[i] == ret) {
5710 state->reply[i] = true;
5716 for (i=0; i<state->node_count; i++) {
5717 if (! state->reply[i]) {
5718 state->done = false;
5724 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5725 struct ctdb_context *ctdb, uint32_t timeout,
5726 uint32_t *pnn_list, int count)
5728 struct ctdb_disable_message disable = { 0 };
5729 struct disable_takeover_runs_state state;
5732 disable.pnn = ctdb->pnn;
5733 disable.srvid = next_srvid(ctdb);
5734 disable.timeout = timeout;
5736 state.pnn_list = pnn_list;
5737 state.node_count = count;
5740 state.reply = talloc_zero_array(mem_ctx, bool, count);
5741 if (state.reply == NULL) {
5745 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5747 disable_takeover_run_handler,
5753 for (i=0; i<count; i++) {
5754 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5763 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5765 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5767 ret = (state.status >= 0 ? 0 : 1);
5771 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5772 disable.srvid, &state);
5776 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5777 int argc, const char **argv)
5779 const char *nodestring = NULL;
5780 struct ctdb_node_map *nodemap, *nodemap2;
5781 struct ctdb_req_control request;
5782 uint32_t *pnn_list, *pnn_list2;
5783 int ret, count, count2;
5790 nodestring = argv[0];
5793 nodemap = get_nodemap(ctdb, false);
5794 if (nodemap == NULL) {
5798 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5802 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5803 mem_ctx, &pnn_list);
5805 fprintf(stderr, "Memory allocation error\n");
5809 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5810 mem_ctx, &pnn_list2);
5812 fprintf(stderr, "Memory allocation error\n");
5816 /* Disable takeover runs on all connected nodes. A reply
5817 * indicating success is needed from each node so all nodes
5818 * will need to be active.
5820 * A check could be added to not allow reloading of IPs when
5821 * there are disconnected nodes. However, this should
5822 * probably be left up to the administrator.
5824 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5827 fprintf(stderr, "Failed to disable takeover runs\n");
5831 /* Now tell all the desired nodes to reload their public IPs.
5832 * Keep trying this until it succeeds. This assumes all
5833 * failures are transient, which might not be true...
5835 ctdb_req_control_reload_public_ips(&request);
5836 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5837 pnn_list2, count2, TIMEOUT(),
5838 &request, NULL, NULL);
5840 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5843 /* It isn't strictly necessary to wait until takeover runs are
5844 * re-enabled but doing so can't hurt.
5846 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5848 fprintf(stderr, "Failed to enable takeover runs\n");
5852 return ipreallocate(mem_ctx, ctdb);
5855 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5856 int argc, const char **argv)
5858 ctdb_sock_addr addr;
5866 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
5868 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
5872 iface = ctdb_sys_find_ifname(&addr);
5873 if (iface == NULL) {
5874 fprintf(stderr, "Failed to find interface for IP %s\n",
5884 static const struct ctdb_cmd {
5886 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5887 bool without_daemon; /* can be run without daemon running ? */
5888 bool remote; /* can be run on remote nodes */
5891 } ctdb_commands[] = {
5892 { "version", control_version, true, false,
5893 "show version of ctdb", NULL },
5894 { "status", control_status, false, true,
5895 "show node status", NULL },
5896 { "uptime", control_uptime, false, true,
5897 "show node uptime", NULL },
5898 { "ping", control_ping, false, true,
5899 "ping all nodes", NULL },
5900 { "runstate", control_runstate, false, true,
5901 "get/check runstate of a node",
5902 "[setup|first_recovery|startup|running]" },
5903 { "getvar", control_getvar, false, true,
5904 "get a tunable variable", "<name>" },
5905 { "setvar", control_setvar, false, true,
5906 "set a tunable variable", "<name> <value>" },
5907 { "listvars", control_listvars, false, true,
5908 "list tunable variables", NULL },
5909 { "statistics", control_statistics, false, true,
5910 "show ctdb statistics", NULL },
5911 { "statisticsreset", control_statistics_reset, false, true,
5912 "reset ctdb statistics", NULL },
5913 { "stats", control_stats, false, true,
5914 "show rolling statistics", "[count]" },
5915 { "ip", control_ip, false, true,
5916 "show public ips", "[all]" },
5917 { "ipinfo", control_ipinfo, false, true,
5918 "show public ip details", "<ip>" },
5919 { "ifaces", control_ifaces, false, true,
5920 "show interfaces", NULL },
5921 { "setifacelink", control_setifacelink, false, true,
5922 "set interface link status", "<iface> up|down" },
5923 { "process-exists", control_process_exists, false, true,
5924 "check if a process exists on a node", "<pid> [<srvid>]" },
5925 { "getdbmap", control_getdbmap, false, true,
5926 "show attached databases", NULL },
5927 { "getdbstatus", control_getdbstatus, false, true,
5928 "show database status", "<dbname|dbid>" },
5929 { "catdb", control_catdb, false, false,
5930 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5931 { "cattdb", control_cattdb, false, false,
5932 "dump local ctdb database", "<dbname|dbid>" },
5933 { "getcapabilities", control_getcapabilities, false, true,
5934 "show node capabilities", NULL },
5935 { "pnn", control_pnn, false, false,
5936 "show the pnn of the currnet node", NULL },
5937 { "lvs", control_lvs, false, false,
5938 "show lvs configuration", "master|list|status" },
5939 { "setdebug", control_setdebug, false, true,
5940 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5941 { "getdebug", control_getdebug, false, true,
5942 "get debug level", NULL },
5943 { "attach", control_attach, false, false,
5944 "attach a database", "<dbname> [persistent|replicated]" },
5945 { "detach", control_detach, false, false,
5946 "detach database(s)", "<dbname|dbid> ..." },
5947 { "dumpmemory", control_dumpmemory, false, true,
5948 "dump ctdbd memory map", NULL },
5949 { "rddumpmemory", control_rddumpmemory, false, true,
5950 "dump recoverd memory map", NULL },
5951 { "getpid", control_getpid, false, true,
5952 "get ctdbd process ID", NULL },
5953 { "disable", control_disable, false, true,
5954 "disable a node", NULL },
5955 { "enable", control_enable, false, true,
5956 "enable a node", NULL },
5957 { "stop", control_stop, false, true,
5958 "stop a node", NULL },
5959 { "continue", control_continue, false, true,
5960 "continue a stopped node", NULL },
5961 { "ban", control_ban, false, true,
5962 "ban a node", "<bantime>"},
5963 { "unban", control_unban, false, true,
5964 "unban a node", NULL },
5965 { "shutdown", control_shutdown, false, true,
5966 "shutdown ctdb daemon", NULL },
5967 { "recover", control_recover, false, true,
5968 "force recovery", NULL },
5969 { "sync", control_ipreallocate, false, true,
5970 "run ip reallocation (deprecated)", NULL },
5971 { "ipreallocate", control_ipreallocate, false, true,
5972 "run ip reallocation", NULL },
5973 { "isnotrecmaster", control_isnotrecmaster, false, false,
5974 "check if local node is the recmaster", NULL },
5975 { "gratarp", control_gratarp, false, true,
5976 "send a gratuitous arp", "<ip> <interface>" },
5977 { "tickle", control_tickle, true, false,
5978 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5979 { "gettickles", control_gettickles, false, true,
5980 "get the list of tickles", "<ip> [<port>]" },
5981 { "addtickle", control_addtickle, false, true,
5982 "add a tickle", "<ip>:<port> <ip>:<port>" },
5983 { "deltickle", control_deltickle, false, true,
5984 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5985 { "listnodes", control_listnodes, true, true,
5986 "list nodes in the cluster", NULL },
5987 { "reloadnodes", control_reloadnodes, false, false,
5988 "reload the nodes file all nodes", NULL },
5989 { "moveip", control_moveip, false, false,
5990 "move an ip address to another node", "<ip> <node>" },
5991 { "addip", control_addip, false, true,
5992 "add an ip address to a node", "<ip/mask> <iface>" },
5993 { "delip", control_delip, false, true,
5994 "delete an ip address from a node", "<ip>" },
5995 { "backupdb", control_backupdb, false, false,
5996 "backup a database into a file", "<dbname|dbid> <file>" },
5997 { "restoredb", control_restoredb, false, false,
5998 "restore a database from a file", "<file> [dbname]" },
5999 { "dumpdbbackup", control_dumpdbbackup, true, false,
6000 "dump database from a backup file", "<file>" },
6001 { "wipedb", control_wipedb, false, false,
6002 "wipe the contents of a database.", "<dbname|dbid>"},
6003 { "recmaster", control_recmaster, false, true,
6004 "show the pnn for the recovery master", NULL },
6005 { "event", control_event, true, false,
6006 "event and event script commands", NULL },
6007 { "scriptstatus", control_scriptstatus, true, false,
6008 "show event script status",
6009 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6010 { "natgw", control_natgw, false, false,
6011 "show natgw configuration", "master|list|status" },
6012 { "getreclock", control_getreclock, false, true,
6013 "get recovery lock file", NULL },
6014 { "setlmasterrole", control_setlmasterrole, false, true,
6015 "set LMASTER role", "on|off" },
6016 { "setrecmasterrole", control_setrecmasterrole, false, true,
6017 "set RECMASTER role", "on|off"},
6018 { "setdbreadonly", control_setdbreadonly, false, true,
6019 "enable readonly records", "<dbname|dbid>" },
6020 { "setdbsticky", control_setdbsticky, false, true,
6021 "enable sticky records", "<dbname|dbid>"},
6022 { "pfetch", control_pfetch, false, false,
6023 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6024 { "pstore", control_pstore, false, false,
6025 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6026 { "pdelete", control_pdelete, false, false,
6027 "delete record from persistent database", "<dbname|dbid> <key>" },
6028 { "ptrans", control_ptrans, false, false,
6029 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6030 { "tfetch", control_tfetch, false, true,
6031 "fetch a record", "<tdb-file> <key> [<file>]" },
6032 { "tstore", control_tstore, false, true,
6033 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6034 { "readkey", control_readkey, false, false,
6035 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6036 { "writekey", control_writekey, false, false,
6037 "write value for a database key", "<dbname|dbid> <key> <value>" },
6038 { "deletekey", control_deletekey, false, false,
6039 "delete a database key", "<dbname|dbid> <key>" },
6040 { "checktcpport", control_checktcpport, true, false,
6041 "check if a service is bound to a specific tcp port or not", "<port>" },
6042 { "getdbseqnum", control_getdbseqnum, false, false,
6043 "get database sequence number", "<dbname|dbid>" },
6044 { "nodestatus", control_nodestatus, false, true,
6045 "show and return node status", "[all|<pnn-list>]" },
6046 { "dbstatistics", control_dbstatistics, false, true,
6047 "show database statistics", "<dbname|dbid>" },
6048 { "reloadips", control_reloadips, false, false,
6049 "reload the public addresses file", "[all|<pnn-list>]" },
6050 { "ipiface", control_ipiface, true, false,
6051 "Find the interface an ip address is hosted on", "<ip>" },
6054 static const struct ctdb_cmd *match_command(const char *command)
6056 const struct ctdb_cmd *cmd;
6059 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6060 cmd = &ctdb_commands[i];
6061 if (strlen(command) == strlen(cmd->name) &&
6062 strncmp(command, cmd->name, strlen(command)) == 0) {
6072 * Show usage message
6074 static void usage_full(void)
6078 poptPrintHelp(pc, stdout, 0);
6079 printf("\nCommands:\n");
6080 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6081 printf(" %-15s %-27s %s\n",
6082 ctdb_commands[i].name,
6083 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6084 ctdb_commands[i].msg);
6088 static void usage(const char *command)
6090 const struct ctdb_cmd *cmd;
6092 if (command == NULL) {
6097 cmd = match_command(command);
6101 poptPrintUsage(pc, stdout, 0);
6102 printf("\nCommands:\n");
6103 printf(" %-15s %-27s %s\n",
6104 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6110 struct poptOption cmdline_options[] = {
6112 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6113 "CTDB socket path", "filename" },
6114 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6116 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6117 "timelimit (in seconds)" },
6118 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6119 "node specification - integer" },
6120 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6121 "enable machine readable output", NULL },
6122 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6123 "specify separator for machine readable output", "CHAR" },
6124 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6125 "enable machine parsable output with separator |", NULL },
6126 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6127 "enable verbose output", NULL },
6128 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6129 "die if runtime exceeds this limit (in seconds)" },
6133 static int process_command(const struct ctdb_cmd *cmd, int argc,
6136 TALLOC_CTX *tmp_ctx;
6137 struct ctdb_context *ctdb;
6140 uint64_t srvid_offset;
6142 tmp_ctx = talloc_new(NULL);
6143 if (tmp_ctx == NULL) {
6144 fprintf(stderr, "Memory allocation error\n");
6148 if (cmd->without_daemon) {
6149 if (options.pnn != -1) {
6151 "Cannot specify node for command %s\n",
6156 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6157 talloc_free(tmp_ctx);
6161 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6163 fprintf(stderr, "Memory allocation error\n");
6167 ctdb->ev = tevent_context_init(ctdb);
6168 if (ctdb->ev == NULL) {
6169 fprintf(stderr, "Failed to initialize tevent\n");
6173 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6175 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6178 if (!find_node_xpnn(ctdb, NULL)) {
6179 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6184 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6185 srvid_offset = getpid() & 0xFFFF;
6186 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6188 if (options.pnn != -1) {
6189 status = verify_pnn(ctdb, options.pnn);
6194 ctdb->cmd_pnn = options.pnn;
6196 ctdb->cmd_pnn = ctdb->pnn;
6199 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6200 fprintf(stderr, "Node cannot be specified for command %s\n",
6205 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6206 talloc_free(tmp_ctx);
6210 talloc_free(tmp_ctx);
6214 static void signal_handler(int sig)
6216 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6219 static void alarm_handler(int sig)
6221 /* Kill any child processes */
6222 signal(SIGTERM, signal_handler);
6228 int main(int argc, const char *argv[])
6231 const char **extra_argv;
6233 const struct ctdb_cmd *cmd;
6234 const char *ctdb_socket;
6240 /* Set default options */
6241 options.socket = CTDB_SOCKET;
6242 options.debuglevelstr = NULL;
6243 options.timelimit = 10;
6245 options.maxruntime = 0;
6248 ctdb_socket = getenv("CTDB_SOCKET");
6249 if (ctdb_socket != NULL) {
6250 options.socket = ctdb_socket;
6253 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6254 POPT_CONTEXT_KEEP_FIRST);
6255 while ((opt = poptGetNextOpt(pc)) != -1) {
6256 fprintf(stderr, "Invalid option %s: %s\n",
6257 poptBadOption(pc, 0), poptStrerror(opt));
6261 if (options.maxruntime == 0) {
6262 const char *ctdb_timeout;
6264 ctdb_timeout = getenv("CTDB_TIMEOUT");
6265 if (ctdb_timeout != NULL) {
6266 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6268 options.maxruntime = 120;
6271 if (options.maxruntime <= 120) {
6272 /* default timeout is 120 seconds */
6273 options.maxruntime = 120;
6276 if (options.machineparsable) {
6277 options.machinereadable = 1;
6280 /* setup the remaining options for the commands */
6282 extra_argv = poptGetArgs(pc);
6285 while (extra_argv[extra_argc]) extra_argc++;
6288 if (extra_argc < 1) {
6292 cmd = match_command(extra_argv[0]);
6294 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6298 /* Enable logging */
6299 setup_logging("ctdb", DEBUG_STDERR);
6300 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6301 DEBUGLEVEL = loglevel;
6303 DEBUGLEVEL = DEBUG_ERR;
6306 signal(SIGALRM, alarm_handler);
6307 alarm(options.maxruntime);
6309 ret = process_command(cmd, extra_argc, extra_argv);
6314 (void)poptFreeContext(pc);