4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
33 #include "ctdb_version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
38 #include "common/db_hash.h"
39 #include "common/logging.h"
40 #include "protocol/protocol.h"
41 #include "protocol/protocol_api.h"
42 #include "common/system.h"
43 #include "client/client.h"
45 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
47 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
48 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
52 const char *debuglevelstr;
60 int printemptyrecords;
67 static poptContext pc;
70 struct tevent_context *ev;
71 struct ctdb_client_context *client;
72 struct ctdb_node_map *nodemap;
73 uint32_t pnn, cmd_pnn;
77 static void usage(const char *command);
83 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
85 return (tv2->tv_sec - tv->tv_sec) +
86 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
89 static struct ctdb_node_and_flags *get_node_by_pnn(
90 struct ctdb_node_map *nodemap,
95 for (i=0; i<nodemap->num; i++) {
96 if (nodemap->node[i].pnn == pnn) {
97 return &nodemap->node[i];
103 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
105 static const struct {
109 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
110 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
111 { NODE_FLAGS_BANNED, "BANNED" },
112 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
113 { NODE_FLAGS_DELETED, "DELETED" },
114 { NODE_FLAGS_STOPPED, "STOPPED" },
115 { NODE_FLAGS_INACTIVE, "INACTIVE" },
117 char *flags_str = NULL;
120 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
121 if (flags & flag_names[i].flag) {
122 if (flags_str == NULL) {
123 flags_str = talloc_asprintf(mem_ctx,
124 "%s", flag_names[i].name);
126 flags_str = talloc_asprintf_append(flags_str,
127 "|%s", flag_names[i].name);
129 if (flags_str == NULL) {
130 return "OUT-OF-MEMORY";
134 if (flags_str == NULL) {
141 static uint64_t next_srvid(struct ctdb_context *ctdb)
148 * Get consistent nodemap information.
150 * If nodemap is already cached, use that. If not get it.
151 * If the current node is BANNED, then get nodemap from "better" node.
153 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
156 struct ctdb_node_map *nodemap;
157 struct ctdb_node_and_flags *node;
158 uint32_t current_node;
162 TALLOC_FREE(ctdb->nodemap);
165 if (ctdb->nodemap != NULL) {
166 return ctdb->nodemap;
169 tmp_ctx = talloc_new(ctdb);
170 if (tmp_ctx == NULL) {
174 current_node = ctdb->pnn;
176 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
177 current_node, TIMEOUT(), &nodemap);
179 fprintf(stderr, "Failed to get nodemap from node %u\n",
184 node = get_node_by_pnn(nodemap, current_node);
185 if (node->flags & NODE_FLAGS_BANNED) {
188 current_node = (current_node + 1) % nodemap->num;
189 node = get_node_by_pnn(nodemap, current_node);
191 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
194 } while (current_node != ctdb->pnn);
196 if (current_node == ctdb->pnn) {
197 /* Tried all nodes in the cluster */
198 fprintf(stderr, "Warning: All nodes are banned.\n");
205 ctdb->nodemap = talloc_steal(ctdb, nodemap);
209 talloc_free(tmp_ctx);
213 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
215 struct ctdb_node_map *nodemap;
223 nodemap = get_nodemap(ctdb, false);
224 if (nodemap == NULL) {
229 for (i=0; i<nodemap->num; i++) {
230 if (nodemap->node[i].pnn == pnn) {
236 fprintf(stderr, "Node %u does not exist\n", pnn);
240 if (nodemap->node[i].flags &
241 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
242 fprintf(stderr, "Node %u has status %s\n", pnn,
243 pretty_print_flags(ctdb, nodemap->node[i].flags));
250 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
251 struct ctdb_node_map *nodemap)
253 struct ctdb_node_map *nodemap2;
255 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
256 if (nodemap2 == NULL) {
260 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
262 if (nodemap2->node == NULL) {
263 talloc_free(nodemap2);
271 * Get the number and the list of matching nodes
273 * nodestring := NULL | all | pnn,[pnn,...]
275 * If nodestring is NULL, use the current node.
277 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
278 const char *nodestring,
279 struct ctdb_node_map **out)
281 struct ctdb_node_map *nodemap, *nodemap2;
282 struct ctdb_node_and_flags *node;
285 nodemap = get_nodemap(ctdb, false);
286 if (nodemap == NULL) {
290 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
291 if (nodemap2 == NULL) {
295 if (nodestring == NULL) {
296 for (i=0; i<nodemap->num; i++) {
297 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
298 nodemap2->node[0] = nodemap->node[i];
307 if (strcmp(nodestring, "all") == 0) {
308 for (i=0; i<nodemap->num; i++) {
309 nodemap2->node[i] = nodemap->node[i];
311 nodemap2->num = nodemap->num;
317 ns = talloc_strdup(mem_ctx, nodestring);
322 tok = strtok(ns, ",");
323 while (tok != NULL) {
327 pnn = (uint32_t)strtoul(tok, &endptr, 0);
328 if (pnn == 0 && tok == endptr) {
329 fprintf(stderr, "Invalid node %s\n", tok);
333 node = get_node_by_pnn(nodemap, pnn);
335 fprintf(stderr, "Node %u does not exist\n",
340 nodemap2->node[nodemap2->num] = *node;
343 tok = strtok(NULL, ",");
352 /* Compare IP address */
353 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
357 if (ip1->sa.sa_family != ip2->sa.sa_family) {
361 switch (ip1->sa.sa_family) {
363 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
364 sizeof(struct in_addr)) == 0);
368 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
369 sizeof(struct in6_addr)) == 0);
376 /* Append a node to a node map with given address and flags */
377 static bool node_map_add(struct ctdb_node_map *nodemap,
378 const char *nstr, uint32_t flags)
382 struct ctdb_node_and_flags *n;
384 if (! parse_ip(nstr, NULL, 0, &addr)) {
385 fprintf(stderr, "Invalid IP address %s\n", nstr);
390 nodemap->node = talloc_realloc(nodemap, nodemap->node,
391 struct ctdb_node_and_flags, num+1);
392 if (nodemap->node == NULL) {
396 n = &nodemap->node[num];
401 nodemap->num = num+1;
405 /* Read a nodes file into a node map */
406 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
412 struct ctdb_node_map *nodemap;
414 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
415 if (nodemap == NULL) {
419 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
424 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
428 for (i=0; i<nlines; i++) {
434 /* strip leading spaces */
435 while((*node == ' ') || (*node == '\t')) {
441 /* strip trailing spaces */
443 ((node[len-1] == ' ') || (node[len-1] == '\t')))
453 /* A "deleted" node is a node that is
454 commented out in the nodes file. This is
455 used instead of removing a line, which
456 would cause subsequent nodes to change
458 flags = NODE_FLAGS_DELETED;
459 node = discard_const("0.0.0.0");
463 if (! node_map_add(nodemap, node, flags)) {
465 TALLOC_FREE(nodemap);
474 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
476 struct ctdb_node_map *nodemap;
478 const char *nodes_list = NULL;
480 if (pnn != CTDB_UNKNOWN_PNN) {
481 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
482 if (nodepath != NULL) {
483 nodes_list = getenv(nodepath);
486 if (nodes_list == NULL) {
487 nodes_list = getenv("CTDB_NODES");
489 if (nodes_list == NULL) {
490 const char *basedir = getenv("CTDB_BASE");
491 if (basedir == NULL) {
492 basedir = CTDB_ETCDIR;
494 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
495 if (nodes_list == NULL) {
496 fprintf(stderr, "Memory allocation error\n");
501 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
502 if (nodemap == NULL) {
503 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
511 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
512 struct ctdb_context *ctdb,
513 struct ctdb_dbid_map *dbmap,
516 struct ctdb_dbid *db = NULL;
520 for (i=0; i<dbmap->num; i++) {
521 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
522 ctdb->pnn, TIMEOUT(),
523 dbmap->dbs[i].db_id, &name);
528 if (strcmp(db_name, name) == 0) {
529 talloc_free(discard_const(name));
538 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
539 const char *db_arg, uint32_t *db_id,
540 const char **db_name, uint8_t *db_flags)
542 struct ctdb_dbid_map *dbmap;
543 struct ctdb_dbid *db = NULL;
545 const char *name = NULL;
548 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
549 ctdb->pnn, TIMEOUT(), &dbmap);
554 if (strncmp(db_arg, "0x", 2) == 0) {
555 id = strtoul(db_arg, NULL, 0);
556 for (i=0; i<dbmap->num; i++) {
557 if (id == dbmap->dbs[i].db_id) {
564 db = db_find(mem_ctx, ctdb, dbmap, name);
568 fprintf(stderr, "No database matching '%s' found\n", db_arg);
573 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
574 ctdb->pnn, TIMEOUT(), id, &name);
583 if (db_name != NULL) {
584 *db_name = talloc_strdup(mem_ctx, name);
586 if (db_flags != NULL) {
587 *db_flags = db->flags;
592 static int h2i(char h)
594 if (h >= 'a' && h <= 'f') {
597 if (h >= 'A' && h <= 'F') {
603 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
610 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
615 data.dsize = len / 2;
616 data.dptr = talloc_size(mem_ctx, data.dsize);
617 if (data.dptr == NULL) {
621 for (i=0; i<data.dsize; i++) {
622 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
629 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
635 if (strncmp(str, "0x", 2) == 0) {
636 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
638 data.dptr = talloc_memdup(mem_ctx, str, len);
639 if (data.dptr == NULL) {
649 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
650 const char *path, int argc, const char **argv)
653 int save_errno, status, ret;
654 const char **new_argv;
657 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
658 if (new_argv == NULL) {
663 for (i=0; i<argc; i++) {
664 new_argv[i+1] = argv[i];
666 new_argv[argc+1] = NULL;
671 talloc_free(new_argv);
672 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
673 command, path, strerror(save_errno));
678 ret = execv(path, discard_const(new_argv));
682 /* Should not happen */
686 talloc_free(new_argv);
688 ret = waitpid(pid, &status, 0);
691 fprintf(stderr, "waitpid() failed for %s - %s\n",
692 command, strerror(save_errno));
696 if (WIFEXITED(status)) {
697 int pstatus = WEXITSTATUS(status);
698 if (WIFSIGNALED(status)) {
699 fprintf(stderr, "%s terminated with signal %d\n",
700 command, WTERMSIG(status));
702 } else if (pstatus >= 64 && pstatus < 255) {
703 fprintf(stderr, "%s failed with error %d\n",
704 command, pstatus-64);
710 } else if (WIFSIGNALED(status)) {
711 fprintf(stderr, "%s terminated with signal %d\n",
712 command, WTERMSIG(status));
723 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
724 int argc, const char **argv)
726 printf("%s\n", CTDB_VERSION_STRING);
730 static bool partially_online(TALLOC_CTX *mem_ctx,
731 struct ctdb_context *ctdb,
732 struct ctdb_node_and_flags *node)
734 struct ctdb_iface_list *iface_list;
738 if (node->flags != 0) {
742 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
743 node->pnn, TIMEOUT(), &iface_list);
749 for (i=0; i < iface_list->num; i++) {
750 if (iface_list->iface[i].link_state == 0) {
759 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
760 struct ctdb_context *ctdb,
761 struct ctdb_node_map *nodemap,
764 struct ctdb_node_and_flags *node;
767 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
771 "Disconnected", options.sep,
772 "Banned", options.sep,
773 "Disabled", options.sep,
774 "Unhealthy", options.sep,
775 "Stopped", options.sep,
776 "Inactive", options.sep,
777 "PartiallyOnline", options.sep,
778 "ThisNode", options.sep);
780 for (i=0; i<nodemap->num; i++) {
781 node = &nodemap->node[i];
782 if (node->flags & NODE_FLAGS_DELETED) {
786 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
788 node->pnn, options.sep,
789 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
791 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
792 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
793 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
795 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
796 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
797 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
798 partially_online(mem_ctx, ctdb, node), options.sep,
799 (node->pnn == mypnn)?'Y':'N', options.sep);
804 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
805 struct ctdb_node_map *nodemap, uint32_t mypnn,
808 struct ctdb_node_and_flags *node;
809 int num_deleted_nodes = 0;
812 for (i=0; i<nodemap->num; i++) {
813 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
819 if (num_deleted_nodes == 0) {
820 printf("Number of nodes:%d\n", nodemap->num);
822 printf("Number of nodes:%d "
823 "(including %d deleted nodes)\n",
824 nodemap->num, num_deleted_nodes);
828 for (i=0; i<nodemap->num; i++) {
829 node = &nodemap->node[i];
830 if (node->flags & NODE_FLAGS_DELETED) {
834 printf("pnn:%u %-16s %s%s\n",
836 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
837 partially_online(mem_ctx, ctdb, node) ?
839 pretty_print_flags(mem_ctx, node->flags),
840 node->pnn == mypnn ? " (THIS NODE)" : "");
844 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
845 struct ctdb_node_map *nodemap, uint32_t mypnn,
846 struct ctdb_vnn_map *vnnmap, int recmode,
851 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
853 if (vnnmap->generation == INVALID_GENERATION) {
854 printf("Generation:INVALID\n");
856 printf("Generation:%u\n", vnnmap->generation);
858 printf("Size:%d\n", vnnmap->size);
859 for (i=0; i<vnnmap->size; i++) {
860 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
863 printf("Recovery mode:%s (%d)\n",
864 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
866 printf("Recovery master:%d\n", recmaster);
869 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
870 int argc, const char **argv)
872 struct ctdb_node_map *nodemap;
873 struct ctdb_vnn_map *vnnmap;
882 nodemap = get_nodemap(ctdb, false);
883 if (nodemap == NULL) {
887 if (options.machinereadable == 1) {
888 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
892 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
893 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
898 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
899 ctdb->cmd_pnn, TIMEOUT(), &recmode);
904 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
905 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
910 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
915 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
916 int argc, const char **argv)
918 struct ctdb_uptime *uptime;
919 int ret, tmp, days, hours, minutes, seconds;
921 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
922 ctdb->cmd_pnn, TIMEOUT(), &uptime);
927 printf("Current time of node %-4u : %s",
928 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
930 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
931 seconds = tmp % 60; tmp /= 60;
932 minutes = tmp % 60; tmp /= 60;
933 hours = tmp % 24; tmp /= 24;
936 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
937 days, hours, minutes, seconds,
938 ctime(&uptime->ctdbd_start_time.tv_sec));
940 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
941 seconds = tmp % 60; tmp /= 60;
942 minutes = tmp % 60; tmp /= 60;
943 hours = tmp % 24; tmp /= 24;
946 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
947 days, hours, minutes, seconds,
948 ctime(&uptime->last_recovery_finished.tv_sec));
950 printf("Duration of last recovery/failover: %lf seconds\n",
951 timeval_delta(&uptime->last_recovery_finished,
952 &uptime->last_recovery_started));
957 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
958 int argc, const char **argv)
961 int ret, num_clients;
963 tv = timeval_current();
964 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
965 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
970 printf("response from %u time=%.6f sec (%d clients)\n",
971 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
975 const char *runstate_to_string(enum ctdb_runstate runstate);
976 enum ctdb_runstate runstate_from_string(const char *runstate_str);
978 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
979 int argc, const char **argv)
981 enum ctdb_runstate runstate;
985 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
986 ctdb->cmd_pnn, TIMEOUT(), &runstate);
992 for (i=0; i<argc; i++) {
993 enum ctdb_runstate t;
996 t = ctdb_runstate_from_string(argv[i]);
997 if (t == CTDB_RUNSTATE_UNKNOWN) {
998 printf("Invalid run state (%s)\n", argv[i]);
1002 if (t == runstate) {
1009 printf("CTDB not in required run state (got %s)\n",
1010 ctdb_runstate_to_string(runstate));
1014 printf("%s\n", ctdb_runstate_to_string(runstate));
1018 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1019 int argc, const char **argv)
1021 struct ctdb_var_list *tun_var_list;
1030 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1031 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1034 "Failed to get list of variables from node %u\n",
1040 for (i=0; i<tun_var_list->count; i++) {
1041 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1048 printf("No such tunable %s\n", argv[0]);
1052 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1053 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1058 printf("%-26s = %u\n", argv[0], value);
1062 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1063 int argc, const char **argv)
1065 struct ctdb_var_list *tun_var_list;
1066 struct ctdb_tunable tunable;
1074 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1075 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1078 "Failed to get list of variables from node %u\n",
1084 for (i=0; i<tun_var_list->count; i++) {
1085 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1092 printf("No such tunable %s\n", argv[0]);
1096 tunable.name = argv[0];
1097 tunable.value = strtoul(argv[1], NULL, 0);
1099 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1100 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1104 "Setting obsolete tunable variable '%s'\n",
1113 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1114 int argc, const char **argv)
1116 struct ctdb_var_list *tun_var_list;
1123 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1124 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1129 for (i=0; i<tun_var_list->count; i++) {
1130 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1139 } stats_fields[] = {
1140 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1141 STATISTICS_FIELD(num_clients),
1142 STATISTICS_FIELD(frozen),
1143 STATISTICS_FIELD(recovering),
1144 STATISTICS_FIELD(num_recoveries),
1145 STATISTICS_FIELD(client_packets_sent),
1146 STATISTICS_FIELD(client_packets_recv),
1147 STATISTICS_FIELD(node_packets_sent),
1148 STATISTICS_FIELD(node_packets_recv),
1149 STATISTICS_FIELD(keepalive_packets_sent),
1150 STATISTICS_FIELD(keepalive_packets_recv),
1151 STATISTICS_FIELD(node.req_call),
1152 STATISTICS_FIELD(node.reply_call),
1153 STATISTICS_FIELD(node.req_dmaster),
1154 STATISTICS_FIELD(node.reply_dmaster),
1155 STATISTICS_FIELD(node.reply_error),
1156 STATISTICS_FIELD(node.req_message),
1157 STATISTICS_FIELD(node.req_control),
1158 STATISTICS_FIELD(node.reply_control),
1159 STATISTICS_FIELD(client.req_call),
1160 STATISTICS_FIELD(client.req_message),
1161 STATISTICS_FIELD(client.req_control),
1162 STATISTICS_FIELD(timeouts.call),
1163 STATISTICS_FIELD(timeouts.control),
1164 STATISTICS_FIELD(timeouts.traverse),
1165 STATISTICS_FIELD(locks.num_calls),
1166 STATISTICS_FIELD(locks.num_current),
1167 STATISTICS_FIELD(locks.num_pending),
1168 STATISTICS_FIELD(locks.num_failed),
1169 STATISTICS_FIELD(total_calls),
1170 STATISTICS_FIELD(pending_calls),
1171 STATISTICS_FIELD(childwrite_calls),
1172 STATISTICS_FIELD(pending_childwrite_calls),
1173 STATISTICS_FIELD(memory_used),
1174 STATISTICS_FIELD(max_hop_count),
1175 STATISTICS_FIELD(total_ro_delegations),
1176 STATISTICS_FIELD(total_ro_revokes),
1179 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1181 static void print_statistics_machine(struct ctdb_statistics *s,
1187 printf("CTDB version%s", options.sep);
1188 printf("Current time of statistics%s", options.sep);
1189 printf("Statistics collected since%s", options.sep);
1190 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1191 printf("%s%s", stats_fields[i].name, options.sep);
1193 printf("num_reclock_ctdbd_latency%s", options.sep);
1194 printf("min_reclock_ctdbd_latency%s", options.sep);
1195 printf("avg_reclock_ctdbd_latency%s", options.sep);
1196 printf("max_reclock_ctdbd_latency%s", options.sep);
1198 printf("num_reclock_recd_latency%s", options.sep);
1199 printf("min_reclock_recd_latency%s", options.sep);
1200 printf("avg_reclock_recd_latency%s", options.sep);
1201 printf("max_reclock_recd_latency%s", options.sep);
1203 printf("num_call_latency%s", options.sep);
1204 printf("min_call_latency%s", options.sep);
1205 printf("avg_call_latency%s", options.sep);
1206 printf("max_call_latency%s", options.sep);
1208 printf("num_lockwait_latency%s", options.sep);
1209 printf("min_lockwait_latency%s", options.sep);
1210 printf("avg_lockwait_latency%s", options.sep);
1211 printf("max_lockwait_latency%s", options.sep);
1213 printf("num_childwrite_latency%s", options.sep);
1214 printf("min_childwrite_latency%s", options.sep);
1215 printf("avg_childwrite_latency%s", options.sep);
1216 printf("max_childwrite_latency%s", options.sep);
1220 printf("%u%s", CTDB_PROTOCOL, options.sep);
1221 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1222 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1223 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1225 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1228 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1229 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1230 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1231 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1233 printf("%u%s", s->reclock.recd.num, options.sep);
1234 printf("%.6f%s", s->reclock.recd.min, options.sep);
1235 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1236 printf("%.6f%s", s->reclock.recd.max, options.sep);
1238 printf("%d%s", s->call_latency.num, options.sep);
1239 printf("%.6f%s", s->call_latency.min, options.sep);
1240 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1241 printf("%.6f%s", s->call_latency.max, options.sep);
1243 printf("%d%s", s->childwrite_latency.num, options.sep);
1244 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1245 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1246 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1250 static void print_statistics(struct ctdb_statistics *s)
1252 int tmp, days, hours, minutes, seconds;
1254 const char *prefix = NULL;
1257 tmp = s->statistics_current_time.tv_sec -
1258 s->statistics_start_time.tv_sec;
1259 seconds = tmp % 60; tmp /= 60;
1260 minutes = tmp % 60; tmp /= 60;
1261 hours = tmp % 24; tmp /= 24;
1264 printf("CTDB version %u\n", CTDB_PROTOCOL);
1265 printf("Current time of statistics : %s",
1266 ctime(&s->statistics_current_time.tv_sec));
1267 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1268 days, hours, minutes, seconds,
1269 ctime(&s->statistics_start_time.tv_sec));
1271 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1272 if (strchr(stats_fields[i].name, '.') != NULL) {
1273 preflen = strcspn(stats_fields[i].name, ".") + 1;
1275 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1276 prefix = stats_fields[i].name;
1277 printf(" %*.*s\n", preflen-1, preflen-1,
1278 stats_fields[i].name);
1283 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1284 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1285 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1288 printf(" hop_count_buckets:");
1289 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1290 printf(" %d", s->hop_count_bucket[i]);
1293 printf(" lock_buckets:");
1294 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1295 printf(" %d", s->locks.buckets[i]);
1298 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1299 "locks_latency MIN/AVG/MAX",
1300 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1301 s->locks.latency.max, s->locks.latency.num);
1303 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1304 "reclock_ctdbd MIN/AVG/MAX",
1305 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1306 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1308 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1309 "reclock_recd MIN/AVG/MAX",
1310 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1311 s->reclock.recd.max, s->reclock.recd.num);
1313 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1314 "call_latency MIN/AVG/MAX",
1315 s->call_latency.min, LATENCY_AVG(s->call_latency),
1316 s->call_latency.max, s->call_latency.num);
1318 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1319 "childwrite_latency MIN/AVG/MAX",
1320 s->childwrite_latency.min,
1321 LATENCY_AVG(s->childwrite_latency),
1322 s->childwrite_latency.max, s->childwrite_latency.num);
1325 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1326 int argc, const char **argv)
1328 struct ctdb_statistics *stats;
1332 usage("statistics");
1335 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1336 ctdb->cmd_pnn, TIMEOUT(), &stats);
1341 if (options.machinereadable) {
1342 print_statistics_machine(stats, true);
1344 print_statistics(stats);
1350 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1351 struct ctdb_context *ctdb,
1352 int argc, const char **argv)
1357 usage("statisticsreset");
1360 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1361 ctdb->cmd_pnn, TIMEOUT());
1369 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1370 int argc, const char **argv)
1372 struct ctdb_statistics_list *slist;
1373 int ret, count = 0, i;
1374 bool show_header = true;
1381 count = atoi(argv[0]);
1384 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1385 ctdb->cmd_pnn, TIMEOUT(), &slist);
1390 for (i=0; i<slist->num; i++) {
1391 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1394 if (options.machinereadable == 1) {
1395 print_statistics_machine(&slist->stats[i],
1397 show_header = false;
1399 print_statistics(&slist->stats[i]);
1401 if (count > 0 && i == count) {
1409 static int ctdb_public_ip_cmp(const void *a, const void *b)
1411 const struct ctdb_public_ip *ip_a = a;
1412 const struct ctdb_public_ip *ip_b = b;
1414 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1417 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1418 struct ctdb_public_ip_list *ips,
1419 struct ctdb_public_ip_info **ipinfo,
1423 char *conf, *avail, *active;
1425 if (options.machinereadable == 1) {
1426 printf("%s%s%s%s%s", options.sep,
1427 "Public IP", options.sep,
1428 "Node", options.sep);
1429 if (options.verbose == 1) {
1430 printf("%s%s%s%s%s%s\n",
1431 "ActiveInterfaces", options.sep,
1432 "AvailableInterfaces", options.sep,
1433 "ConfiguredInterfaces", options.sep);
1439 printf("Public IPs on ALL nodes\n");
1441 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1445 for (i = 0; i < ips->num; i++) {
1447 if (options.machinereadable == 1) {
1448 printf("%s%s%s%d%s", options.sep,
1449 ctdb_sock_addr_to_string(
1450 mem_ctx, &ips->ip[i].addr),
1452 (int)ips->ip[i].pnn, options.sep);
1454 printf("%s", ctdb_sock_addr_to_string(
1455 mem_ctx, &ips->ip[i].addr));
1458 if (options.verbose == 0) {
1459 if (options.machinereadable == 1) {
1462 printf(" %d\n", (int)ips->ip[i].pnn);
1471 if (ipinfo[i] == NULL) {
1475 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1476 struct ctdb_iface *iface;
1478 iface = &ipinfo[i]->ifaces->iface[j];
1480 conf = talloc_strdup(mem_ctx, iface->name);
1482 conf = talloc_asprintf_append(
1483 conf, ",%s", iface->name);
1486 if (ipinfo[i]->active_idx == j) {
1487 active = iface->name;
1490 if (iface->link_state == 0) {
1494 if (avail == NULL) {
1495 avail = talloc_strdup(mem_ctx, iface->name);
1497 avail = talloc_asprintf_append(
1498 avail, ",%s", iface->name);
1504 if (options.machinereadable == 1) {
1505 printf("%s%s%s%s%s%s\n",
1506 active ? active : "", options.sep,
1507 avail ? avail : "", options.sep,
1508 conf ? conf : "", options.sep);
1510 printf(" node[%d] active[%s] available[%s]"
1511 " configured[%s]\n",
1512 (int)ips->ip[i].pnn, active ? active : "",
1513 avail ? avail : "", conf ? conf : "");
1518 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1519 size_t datalen, void *private_data)
1521 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1522 private_data, struct ctdb_public_ip_list);
1523 struct ctdb_public_ip *ip;
1525 ip = (struct ctdb_public_ip *)databuf;
1526 ips->ip[ips->num] = *ip;
1532 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1533 struct ctdb_public_ip_list **out)
1535 struct ctdb_node_map *nodemap;
1536 struct ctdb_public_ip_list *ips;
1537 struct db_hash_context *ipdb;
1539 int ret, count, i, j;
1541 nodemap = get_nodemap(ctdb, false);
1542 if (nodemap == NULL) {
1546 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1551 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1557 for (i=0; i<count; i++) {
1558 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1559 pnn_list[i], TIMEOUT(),
1565 for (j=0; j<ips->num; j++) {
1566 struct ctdb_public_ip ip;
1568 ip.pnn = ips->ip[j].pnn;
1569 ip.addr = ips->ip[j].addr;
1571 if (pnn_list[i] == ip.pnn) {
1572 /* Node claims IP is hosted on it, so
1573 * save that information
1575 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1577 (uint8_t *)&ip, sizeof(ip));
1582 /* Node thinks IP is hosted elsewhere,
1583 * so overwrite with CTDB_UNKNOWN_PNN
1584 * if there's no existing entry
1586 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1588 if (ret == ENOENT) {
1589 ip.pnn = CTDB_UNKNOWN_PNN;
1590 ret = db_hash_add(ipdb,
1591 (uint8_t *)&ip.addr,
1605 talloc_free(pnn_list);
1607 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1612 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1617 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1618 if (ips->ip == NULL) {
1622 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1627 if (count != ips->num) {
1641 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1642 int argc, const char **argv)
1644 struct ctdb_public_ip_list *ips;
1645 struct ctdb_public_ip_info **ipinfo;
1647 bool do_all = false;
1654 if (strcmp(argv[0], "all") == 0) {
1662 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1664 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1665 ctdb->cmd_pnn, TIMEOUT(),
1672 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1673 ctdb_public_ip_cmp);
1675 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1676 if (ipinfo == NULL) {
1680 for (i=0; i<ips->num; i++) {
1683 pnn = ips->ip[i].pnn;
1685 pnn = ctdb->cmd_pnn;
1687 if (pnn == CTDB_UNKNOWN_PNN) {
1691 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1693 TIMEOUT(), &ips->ip[i].addr,
1700 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1704 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1705 int argc, const char **argv)
1707 struct ctdb_public_ip_info *ipinfo;
1708 ctdb_sock_addr addr;
1715 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1716 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1720 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1721 ctdb->cmd_pnn, TIMEOUT(), &addr,
1725 printf("Node %u does not know about IP %s\n",
1726 ctdb->cmd_pnn, argv[0]);
1731 printf("Public IP[%s] info on node %u\n",
1732 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1735 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1736 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1737 ipinfo->ip.pnn, ipinfo->ifaces->num);
1739 for (i=0; i<ipinfo->ifaces->num; i++) {
1740 struct ctdb_iface *iface;
1742 iface = &ipinfo->ifaces->iface[i];
1743 iface->name[CTDB_IFACE_SIZE] = '\0';
1744 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1746 iface->link_state == 0 ? "down" : "up",
1748 (i == ipinfo->active_idx) ? " (active)" : "");
1754 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1755 int argc, const char **argv)
1757 struct ctdb_iface_list *ifaces;
1764 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1765 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1770 if (ifaces->num == 0) {
1771 printf("No interfaces configured on node %u\n",
1776 if (options.machinereadable) {
1777 printf("%s%s%s%s%s%s%s\n", options.sep,
1778 "Name", options.sep,
1779 "LinkStatus", options.sep,
1780 "References", options.sep);
1782 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1785 for (i=0; i<ifaces->num; i++) {
1786 if (options.machinereadable) {
1787 printf("%s%s%s%u%s%u%s\n", options.sep,
1788 ifaces->iface[i].name, options.sep,
1789 ifaces->iface[i].link_state, options.sep,
1790 ifaces->iface[i].references, options.sep);
1792 printf("name:%s link:%s references:%u\n",
1793 ifaces->iface[i].name,
1794 ifaces->iface[i].link_state ? "up" : "down",
1795 ifaces->iface[i].references);
1802 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1803 int argc, const char **argv)
1805 struct ctdb_iface_list *ifaces;
1806 struct ctdb_iface *iface;
1810 usage("setifacelink");
1813 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1814 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1818 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1819 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1822 "Failed to get interface information from node %u\n",
1828 for (i=0; i<ifaces->num; i++) {
1829 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1830 iface = &ifaces->iface[i];
1835 if (iface == NULL) {
1836 printf("Interface %s not configured on node %u\n",
1837 argv[0], ctdb->cmd_pnn);
1841 if (strcmp(argv[1], "up") == 0) {
1842 iface->link_state = 1;
1843 } else if (strcmp(argv[1], "down") == 0) {
1844 iface->link_state = 0;
1846 usage("setifacelink");
1850 iface->references = 0;
1852 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1853 ctdb->cmd_pnn, TIMEOUT(), iface);
1861 static int control_process_exists(TALLOC_CTX *mem_ctx,
1862 struct ctdb_context *ctdb,
1863 int argc, const char **argv)
1869 usage("process-exists");
1872 pid = atoi(argv[0]);
1873 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1874 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1880 printf("PID %u exists\n", pid);
1882 printf("PID %u does not exist\n", pid);
1887 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1888 int argc, const char **argv)
1890 struct ctdb_dbid_map *dbmap;
1897 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1898 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1903 if (options.machinereadable == 1) {
1904 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1907 "Name", options.sep,
1908 "Path", options.sep,
1909 "Persistent", options.sep,
1910 "Sticky", options.sep,
1911 "Unhealthy", options.sep,
1912 "Readonly", options.sep);
1914 printf("Number of databases:%d\n", dbmap->num);
1917 for (i=0; i<dbmap->num; i++) {
1926 db_id = dbmap->dbs[i].db_id;
1928 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1929 ctdb->cmd_pnn, TIMEOUT(), db_id,
1935 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1936 ctdb->cmd_pnn, TIMEOUT(), db_id,
1942 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1943 ctdb->cmd_pnn, TIMEOUT(), db_id,
1949 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1950 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1951 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1953 if (options.machinereadable == 1) {
1954 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s\n",
1959 !! (persistent), options.sep,
1960 !! (sticky), options.sep,
1961 !! (health), options.sep,
1962 !! (readonly), options.sep);
1964 printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
1966 persistent ? " PERSISTENT" : "",
1967 sticky ? " STICKY" : "",
1968 readonly ? " READONLY" : "",
1969 health ? " UNHEALTHY" : "");
1972 talloc_free(discard_const(name));
1973 talloc_free(discard_const(path));
1974 talloc_free(discard_const(health));
1980 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1981 int argc, const char **argv)
1984 const char *db_name, *db_path, *db_health;
1989 usage("getdbstatus");
1992 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
1996 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1997 ctdb->cmd_pnn, TIMEOUT(), db_id,
2003 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2004 ctdb->cmd_pnn, TIMEOUT(), db_id,
2010 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2011 printf("PERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
2012 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2013 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2014 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"),
2015 (db_health ? db_health : "OK"));
2019 struct dump_record_state {
2023 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2025 static void dump_tdb_data(const char *name, TDB_DATA val)
2029 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2030 for (i=0; i<val.dsize; i++) {
2031 if (ISASCII(val.dptr[i])) {
2032 fprintf(stdout, "%c", val.dptr[i]);
2034 fprintf(stdout, "\\%02X", val.dptr[i]);
2037 fprintf(stdout, "\"\n");
2040 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2042 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2043 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2044 fprintf(stdout, "flags: 0x%08x", header->flags);
2045 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2046 fprintf(stdout, " MIGRATED_WITH_DATA");
2048 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2049 fprintf(stdout, " VACUUM_MIGRATED");
2051 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2052 fprintf(stdout, " AUTOMATIC");
2054 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2055 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2057 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2058 fprintf(stdout, " RO_HAVE_READONLY");
2060 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2061 fprintf(stdout, " RO_REVOKING_READONLY");
2063 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2064 fprintf(stdout, " RO_REVOKE_COMPLETE");
2066 fprintf(stdout, "\n");
2070 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2071 TDB_DATA key, TDB_DATA data, void *private_data)
2073 struct dump_record_state *state =
2074 (struct dump_record_state *)private_data;
2078 dump_tdb_data("key", key);
2079 dump_ltdb_header(header);
2080 dump_tdb_data("data", data);
2081 fprintf(stdout, "\n");
2086 struct traverse_state {
2087 TALLOC_CTX *mem_ctx;
2089 ctdb_rec_parser_func_t func;
2090 struct dump_record_state sub_state;
2093 static void traverse_handler(uint64_t srvid, TDB_DATA data, void *private_data)
2095 struct traverse_state *state = (struct traverse_state *)private_data;
2096 struct ctdb_rec_data *rec;
2097 struct ctdb_ltdb_header header;
2100 ret = ctdb_rec_data_pull(data.dptr, data.dsize, state->mem_ctx, &rec);
2105 if (rec->key.dsize == 0 && rec->data.dsize == 0) {
2107 /* end of traverse */
2112 ret = ctdb_ltdb_header_extract(&rec->data, &header);
2118 if (rec->data.dsize == 0) {
2123 ret = state->func(rec->reqid, &header, rec->key, rec->data,
2131 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2132 int argc, const char **argv)
2134 struct ctdb_db_context *db;
2135 const char *db_name;
2138 struct ctdb_traverse_start_ext traverse;
2139 struct traverse_state state;
2146 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2150 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2153 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2158 ZERO_STRUCT(traverse);
2160 traverse.db_id = db_id;
2162 traverse.srvid = next_srvid(ctdb);
2163 traverse.withemptyrecords = false;
2165 state.mem_ctx = mem_ctx;
2167 state.func = dump_record;
2168 state.sub_state.count = 0;
2170 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2172 traverse_handler, &state);
2177 ret = ctdb_ctrl_traverse_start_ext(mem_ctx, ctdb->ev, ctdb->client,
2178 ctdb->cmd_pnn, TIMEOUT(),
2184 ctdb_client_wait(ctdb->ev, &state.done);
2186 printf("Dumped %u records\n", state.sub_state.count);
2188 ret = ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2189 traverse.srvid, &state);
2197 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2198 int argc, const char **argv)
2200 struct ctdb_db_context *db;
2201 const char *db_name;
2204 struct dump_record_state state;
2211 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2215 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2218 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2223 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2225 printf("Dumped %u record(s)\n", state.count);
2230 static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2231 int argc, const char **argv)
2236 usage("getmonmode");
2239 ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
2240 ctdb->cmd_pnn, TIMEOUT(), &mode);
2246 (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
2250 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2251 struct ctdb_context *ctdb,
2252 int argc, const char **argv)
2258 usage("getcapabilities");
2261 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2262 ctdb->cmd_pnn, TIMEOUT(), &caps);
2267 if (options.machinereadable == 1) {
2268 printf("%s%s%s%s%s\n",
2270 "RECMASTER", options.sep,
2271 "LMASTER", options.sep);
2272 printf("%s%d%s%d%s\n", options.sep,
2273 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2274 !! (caps & CTDB_CAP_LMASTER), options.sep);
2276 printf("RECMASTER: %s\n",
2277 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2278 printf("LMASTER: %s\n",
2279 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2285 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2286 int argc, const char **argv)
2288 printf("%u\n", ctdb_client_pnn(ctdb->client));
2292 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2293 int argc, const char **argv)
2295 char *t, *lvs_helper = NULL;
2301 t = getenv("CTDB_LVS_HELPER");
2303 lvs_helper = talloc_strdup(mem_ctx, t);
2305 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2306 CTDB_HELPER_BINDIR);
2309 if (lvs_helper == NULL) {
2310 fprintf(stderr, "Unable to set LVS helper\n");
2314 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2317 static int control_disable_monitor(TALLOC_CTX *mem_ctx,
2318 struct ctdb_context *ctdb,
2319 int argc, const char **argv)
2324 usage("disablemonitor");
2327 ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2328 ctdb->cmd_pnn, TIMEOUT());
2336 static int control_enable_monitor(TALLOC_CTX *mem_ctx,
2337 struct ctdb_context *ctdb,
2338 int argc, const char **argv)
2343 usage("enablemonitor");
2346 ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2347 ctdb->cmd_pnn, TIMEOUT());
2355 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2356 int argc, const char **argv)
2366 found = debug_level_parse(argv[0], &log_level);
2369 "Invalid debug level '%s'. Valid levels are:\n",
2371 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2375 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2376 ctdb->cmd_pnn, TIMEOUT(), log_level);
2384 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2385 int argc, const char **argv)
2388 const char *log_str;
2395 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2396 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2401 log_str = debug_level_to_string(loglevel);
2402 printf("%s\n", log_str);
2407 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2408 int argc, const char **argv)
2410 const char *db_name;
2411 uint8_t db_flags = 0;
2414 if (argc < 1 || argc > 2) {
2420 if (strcmp(argv[1], "persistent") == 0) {
2421 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2422 } else if (strcmp(argv[1], "readonly") == 0) {
2423 db_flags = CTDB_DB_FLAGS_READONLY;
2424 } else if (strcmp(argv[1], "sticky") == 0) {
2425 db_flags = CTDB_DB_FLAGS_STICKY;
2431 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2440 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2441 int argc, const char **argv)
2443 const char *db_name;
2446 struct ctdb_node_map *nodemap;
2454 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2455 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2460 if (recmode == CTDB_RECOVERY_ACTIVE) {
2461 fprintf(stderr, "Database cannot be detached"
2462 " when recovery is active\n");
2466 nodemap = get_nodemap(ctdb, false);
2467 if (nodemap == NULL) {
2471 for (i=0; i<nodemap->num; i++) {
2474 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2477 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2480 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2481 fprintf(stderr, "Database cannot be detached on"
2482 " inactive (stopped or banned) node %u\n",
2483 nodemap->node[i].pnn);
2487 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2488 nodemap->node[i].pnn, TIMEOUT(),
2489 "AllowClientDBAttach", &value);
2492 "Unable to get tunable AllowClientDBAttach"
2493 " from node %u\n", nodemap->node[i].pnn);
2499 "Database access is still active on node %u."
2500 " Set AllowclientDBAttach=0 on all nodes.\n",
2501 nodemap->node[i].pnn);
2507 for (i=0; i<argc; i++) {
2508 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2513 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
2515 "Persistent database %s cannot be detached\n",
2520 ret = ctdb_detach(mem_ctx, ctdb->ev, ctdb->client,
2523 fprintf(stderr, "Database %s detach failed\n", db_name);
2531 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2532 int argc, const char **argv)
2534 const char *mem_str;
2538 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2539 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2544 n = write(1, mem_str, strlen(mem_str)+1);
2545 if (n < 0 || n != strlen(mem_str)+1) {
2546 fprintf(stderr, "Failed to write talloc summary\n");
2553 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2555 bool *done = (bool *)private_data;
2558 n = write(1, data.dptr, data.dsize);
2559 if (n < 0 || n != data.dsize) {
2560 fprintf(stderr, "Failed to write talloc summary\n");
2566 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2567 int argc, const char **argv)
2569 struct ctdb_srvid_message msg = { 0 };
2573 msg.pnn = ctdb->pnn;
2574 msg.srvid = next_srvid(ctdb);
2576 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2577 msg.srvid, dump_memory, &done);
2582 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2583 ctdb->cmd_pnn, &msg);
2588 ctdb_client_wait(ctdb->ev, &done);
2592 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2593 int argc, const char **argv)
2598 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2599 ctdb->cmd_pnn, TIMEOUT(), &pid);
2604 printf("%u\n", pid);
2608 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2609 const char *desc, uint32_t flag, bool set_flag)
2611 struct ctdb_node_map *nodemap;
2614 nodemap = get_nodemap(ctdb, false);
2615 if (nodemap == NULL) {
2619 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2620 if (set_flag == flag_is_set) {
2622 fprintf(stderr, "Node %u is already %s\n",
2623 ctdb->cmd_pnn, desc);
2625 fprintf(stderr, "Node %u is not %s\n",
2626 ctdb->cmd_pnn, desc);
2634 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2635 uint32_t flag, bool set_flag)
2637 struct ctdb_node_map *nodemap;
2641 nodemap = get_nodemap(ctdb, true);
2642 if (nodemap == NULL) {
2644 "Failed to get nodemap, trying again\n");
2649 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2650 if (flag_is_set == set_flag) {
2658 struct ipreallocate_state {
2663 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2666 struct ipreallocate_state *state =
2667 (struct ipreallocate_state *)private_data;
2669 if (data.dsize != sizeof(int)) {
2674 state->status = *(int *)data.dptr;
2678 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2680 struct ctdb_srvid_message msg = { 0 };
2681 struct ipreallocate_state state;
2684 msg.pnn = ctdb->pnn;
2685 msg.srvid = next_srvid(ctdb);
2688 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2690 ipreallocate_handler, &state);
2696 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2698 CTDB_BROADCAST_CONNECTED,
2704 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2710 if (state.status >= 0) {
2719 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2724 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2725 int argc, const char **argv)
2733 ret = check_flags(mem_ctx, ctdb, "disabled",
2734 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2739 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2740 ctdb->cmd_pnn, TIMEOUT(),
2741 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2744 "Failed to set DISABLED flag on node %u\n",
2749 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2750 return ipreallocate(mem_ctx, ctdb);
2753 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2754 int argc, const char **argv)
2762 ret = check_flags(mem_ctx, ctdb, "disabled",
2763 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2768 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2769 ctdb->cmd_pnn, TIMEOUT(),
2770 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2772 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2777 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2778 return ipreallocate(mem_ctx, ctdb);
2781 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2782 int argc, const char **argv)
2790 ret = check_flags(mem_ctx, ctdb, "stopped",
2791 NODE_FLAGS_STOPPED, true);
2796 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2797 ctdb->cmd_pnn, TIMEOUT());
2799 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2803 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2804 return ipreallocate(mem_ctx, ctdb);
2807 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2808 int argc, const char **argv)
2816 ret = check_flags(mem_ctx, ctdb, "stopped",
2817 NODE_FLAGS_STOPPED, false);
2822 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2823 ctdb->cmd_pnn, TIMEOUT());
2825 fprintf(stderr, "Failed to continue stopped node %u\n",
2830 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2831 return ipreallocate(mem_ctx, ctdb);
2834 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2835 int argc, const char **argv)
2837 struct ctdb_ban_state ban_state;
2844 ret = check_flags(mem_ctx, ctdb, "banned",
2845 NODE_FLAGS_BANNED, true);
2850 ban_state.pnn = ctdb->cmd_pnn;
2851 ban_state.time = strtoul(argv[0], NULL, 0);
2853 if (ban_state.time == 0) {
2854 fprintf(stderr, "Ban time cannot be zero\n");
2858 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2859 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2861 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2865 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2866 return ipreallocate(mem_ctx, ctdb);
2870 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2871 int argc, const char **argv)
2873 struct ctdb_ban_state ban_state;
2880 ret = check_flags(mem_ctx, ctdb, "banned",
2881 NODE_FLAGS_BANNED, false);
2886 ban_state.pnn = ctdb->cmd_pnn;
2889 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2890 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2892 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2896 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2897 return ipreallocate(mem_ctx, ctdb);
2901 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2902 int argc, const char **argv)
2910 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2911 ctdb->cmd_pnn, TIMEOUT());
2913 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2920 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2921 uint32_t *generation)
2925 struct ctdb_vnn_map *vnnmap;
2929 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2930 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2932 fprintf(stderr, "Failed to find recovery master\n");
2936 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2937 recmaster, TIMEOUT(), &recmode);
2939 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2944 if (recmode == CTDB_RECOVERY_ACTIVE) {
2949 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2950 recmaster, TIMEOUT(), &vnnmap);
2952 fprintf(stderr, "Failed to get generation from node %u\n",
2957 if (vnnmap->generation == INVALID_GENERATION) {
2958 talloc_free(vnnmap);
2963 *generation = vnnmap->generation;
2964 talloc_free(vnnmap);
2969 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2970 int argc, const char **argv)
2972 uint32_t generation, next_generation;
2979 ret = get_generation(mem_ctx, ctdb, &generation);
2984 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2985 ctdb->cmd_pnn, TIMEOUT(),
2986 CTDB_RECOVERY_ACTIVE);
2988 fprintf(stderr, "Failed to set recovery mode active\n");
2993 ret = get_generation(mem_ctx, ctdb, &next_generation);
2996 "Failed to confirm end of recovery\n");
3000 if (next_generation != generation) {
3010 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3011 int argc, const char **argv)
3014 usage("ipreallocate");
3017 return ipreallocate(mem_ctx, ctdb);
3020 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
3021 struct ctdb_context *ctdb,
3022 int argc, const char **argv)
3028 usage("isnotrecmaster");
3031 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
3032 ctdb->pnn, TIMEOUT(), &recmaster);
3034 fprintf(stderr, "Failed to get recmaster\n");
3038 if (recmaster != ctdb->pnn) {
3039 printf("this node is not the recmaster\n");
3043 printf("this node is the recmaster\n");
3047 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3048 int argc, const char **argv)
3050 struct ctdb_addr_info addr_info;
3057 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
3058 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3061 addr_info.iface = argv[1];
3063 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3064 ctdb->cmd_pnn, TIMEOUT(),
3067 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3075 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3076 int argc, const char **argv)
3078 ctdb_sock_addr src, dst;
3081 if (argc != 0 && argc != 2) {
3086 struct ctdb_connection *clist;
3090 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3096 for (i=0; i<count; i++) {
3097 ret = ctdb_sys_send_tcp(&clist[i].src,
3107 if (num_failed > 0) {
3108 fprintf(stderr, "Failed to send %d tickles\n",
3117 if (! parse_ip_port(argv[0], &src)) {
3118 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3122 if (! parse_ip_port(argv[1], &dst)) {
3123 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3127 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3129 fprintf(stderr, "Failed to send tickle ack\n");
3136 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3137 int argc, const char **argv)
3139 ctdb_sock_addr addr;
3140 struct ctdb_tickle_list *tickles;
3144 if (argc < 1 || argc > 2) {
3145 usage("gettickles");
3149 port = strtoul(argv[1], NULL, 10);
3152 if (! parse_ip(argv[0], NULL, port, &addr)) {
3153 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3157 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3158 ctdb->cmd_pnn, TIMEOUT(), &addr,
3161 fprintf(stderr, "Failed to get list of connections\n");
3165 if (options.machinereadable) {
3166 printf("%s%s%s%s%s%s%s%s%s\n",
3168 "Source IP", options.sep,
3169 "Port", options.sep,
3170 "Destiation IP", options.sep,
3171 "Port", options.sep);
3172 for (i=0; i<tickles->num; i++) {
3173 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3174 ctdb_sock_addr_to_string(
3175 mem_ctx, &tickles->conn[i].src),
3177 ntohs(tickles->conn[i].src.ip.sin_port),
3179 ctdb_sock_addr_to_string(
3180 mem_ctx, &tickles->conn[i].dst),
3182 ntohs(tickles->conn[i].dst.ip.sin_port),
3186 printf("Connections for IP: %s\n",
3187 ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
3188 printf("Num connections: %u\n", tickles->num);
3189 for (i=0; i<tickles->num; i++) {
3190 printf("SRC: %s:%u DST: %s:%u\n",
3191 ctdb_sock_addr_to_string(
3192 mem_ctx, &tickles->conn[i].src),
3193 ntohs(tickles->conn[i].src.ip.sin_port),
3194 ctdb_sock_addr_to_string(
3195 mem_ctx, &tickles->conn[i].dst),
3196 ntohs(tickles->conn[i].dst.ip.sin_port));
3200 talloc_free(tickles);
3204 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3205 struct ctdb_connection *conn);
3207 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3209 struct process_clist_state {
3210 struct ctdb_connection *clist;
3212 int num_failed, num_total;
3213 clist_reply_func reply_func;
3216 static void process_clist_done(struct tevent_req *subreq);
3218 static struct tevent_req *process_clist_send(
3219 TALLOC_CTX *mem_ctx,
3220 struct ctdb_context *ctdb,
3221 struct ctdb_connection *clist,
3223 clist_request_func request_func,
3224 clist_reply_func reply_func)
3226 struct tevent_req *req, *subreq;
3227 struct process_clist_state *state;
3228 struct ctdb_req_control request;
3231 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3236 state->clist = clist;
3237 state->count = count;
3238 state->reply_func = reply_func;
3240 for (i=0; i<count; i++) {
3241 request_func(&request, &clist[i]);
3242 subreq = ctdb_client_control_send(state, ctdb->ev,
3243 ctdb->client, ctdb->cmd_pnn,
3244 TIMEOUT(), &request);
3245 if (tevent_req_nomem(subreq, req)) {
3246 return tevent_req_post(req, ctdb->ev);
3248 tevent_req_set_callback(subreq, process_clist_done, req);
3254 static void process_clist_done(struct tevent_req *subreq)
3256 struct tevent_req *req = tevent_req_callback_data(
3257 subreq, struct tevent_req);
3258 struct process_clist_state *state = tevent_req_data(
3259 req, struct process_clist_state);
3260 struct ctdb_reply_control *reply;
3264 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3265 TALLOC_FREE(subreq);
3267 state->num_failed += 1;
3271 ret = state->reply_func(reply);
3273 state->num_failed += 1;
3278 state->num_total += 1;
3279 if (state->num_total == state->count) {
3280 tevent_req_done(req);
3284 static int process_clist_recv(struct tevent_req *req)
3286 struct process_clist_state *state = tevent_req_data(
3287 req, struct process_clist_state);
3289 return state->num_failed;
3292 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3293 int argc, const char **argv)
3295 struct ctdb_connection conn;
3298 if (argc != 0 && argc != 2) {
3303 struct ctdb_connection *clist;
3304 struct tevent_req *req;
3307 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3315 req = process_clist_send(mem_ctx, ctdb, clist, count,
3316 ctdb_req_control_tcp_add_delayed_update,
3317 ctdb_reply_control_tcp_add_delayed_update);
3323 tevent_req_poll(req, ctdb->ev);
3326 ret = process_clist_recv(req);
3328 fprintf(stderr, "Failed to add %d tickles\n", ret);
3335 if (! parse_ip_port(argv[0], &conn.src)) {
3336 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3339 if (! parse_ip_port(argv[1], &conn.dst)) {
3340 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3344 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3345 ctdb->client, ctdb->cmd_pnn,
3348 fprintf(stderr, "Failed to register connection\n");
3355 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3356 int argc, const char **argv)
3358 struct ctdb_connection conn;
3361 if (argc != 0 && argc != 2) {
3366 struct ctdb_connection *clist;
3367 struct tevent_req *req;
3370 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3378 req = process_clist_send(mem_ctx, ctdb, clist, count,
3379 ctdb_req_control_tcp_remove,
3380 ctdb_reply_control_tcp_remove);
3386 tevent_req_poll(req, ctdb->ev);
3389 ret = process_clist_recv(req);
3391 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3398 if (! parse_ip_port(argv[0], &conn.src)) {
3399 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3402 if (! parse_ip_port(argv[1], &conn.dst)) {
3403 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3407 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3408 ctdb->cmd_pnn, TIMEOUT(), &conn);
3410 fprintf(stderr, "Failed to unregister connection\n");
3417 static int control_check_srvids(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3418 int argc, const char **argv)
3425 usage("check_srvids");
3428 srvid = talloc_array(mem_ctx, uint64_t, argc);
3429 if (srvid == NULL) {
3430 fprintf(stderr, "Memory allocation error\n");
3434 for (i=0; i<argc; i++) {
3435 srvid[i] = strtoull(argv[i], NULL, 0);
3438 ret = ctdb_ctrl_check_srvids(mem_ctx, ctdb->ev, ctdb->client,
3439 ctdb->cmd_pnn, TIMEOUT(), srvid, argc,
3442 fprintf(stderr, "Failed to check srvids on node %u\n",
3447 for (i=0; i<argc; i++) {
3448 printf("SRVID 0x%" PRIx64 " %s\n", srvid[i],
3449 (result[i] ? "exists" : "does not exist"));
3455 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3456 int argc, const char **argv)
3458 struct ctdb_node_map *nodemap;
3465 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3466 if (nodemap == NULL) {
3470 for (i=0; i<nodemap->num; i++) {
3471 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3475 if (options.machinereadable) {
3476 printf("%s%u%s%s%s\n", options.sep,
3477 nodemap->node[i].pnn, options.sep,
3478 ctdb_sock_addr_to_string(
3479 mem_ctx, &nodemap->node[i].addr),
3483 ctdb_sock_addr_to_string(
3484 mem_ctx, &nodemap->node[i].addr));
3491 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3492 struct ctdb_node_map *nodemap2)
3496 if (nodemap1->num != nodemap2->num) {
3500 for (i=0; i<nodemap1->num; i++) {
3501 struct ctdb_node_and_flags *n1, *n2;
3503 n1 = &nodemap1->node[i];
3504 n2 = &nodemap2->node[i];
3506 if ((n1->pnn != n2->pnn) ||
3507 (n1->flags != n2->flags) ||
3508 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3516 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3517 struct ctdb_node_map *nm,
3518 struct ctdb_node_map *fnm,
3522 bool check_failed = false;
3526 for (i=0; i<nm->num; i++) {
3527 if (i >= fnm->num) {
3529 "Node %u (%s) missing from nodes file\n",
3531 ctdb_sock_addr_to_string(
3532 mem_ctx, &nm->node[i].addr));
3533 check_failed = true;
3536 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3537 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3538 /* Node remains deleted */
3542 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3543 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3544 /* Node not newly nor previously deleted */
3545 if (! ctdb_same_ip(&nm->node[i].addr,
3546 &fnm->node[i].addr)) {
3548 "Node %u has changed IP address"
3549 " (was %s, now %s)\n",
3551 ctdb_sock_addr_to_string(
3552 mem_ctx, &nm->node[i].addr),
3553 ctdb_sock_addr_to_string(
3554 mem_ctx, &fnm->node[i].addr));
3555 check_failed = true;
3557 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3559 "WARNING: Node %u is disconnected."
3560 " You MUST fix this node manually!\n",
3567 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3568 /* Node is being deleted */
3569 printf("Node %u is DELETED\n", nm->node[i].pnn);
3571 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3573 "ERROR: Node %u is still connected\n",
3575 check_failed = true;
3580 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3581 /* Node was previously deleted */
3582 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3589 "ERROR: Nodes will not be reloaded due to previous error\n");
3593 /* Leftover nodes in file are NEW */
3594 for (; i < fnm->num; i++) {
3595 printf("Node %u is NEW\n", fnm->node[i].pnn);
3602 struct disable_recoveries_state {
3610 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3613 struct disable_recoveries_state *state =
3614 (struct disable_recoveries_state *)private_data;
3617 if (data.dsize != sizeof(int)) {
3622 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3623 ret = *(int *)data.dptr;
3625 state->status = ret;
3629 for (i=0; i<state->node_count; i++) {
3630 if (state->pnn_list[i] == ret) {
3631 state->reply[i] = true;
3637 for (i=0; i<state->node_count; i++) {
3638 if (! state->reply[i]) {
3639 state->done = false;
3645 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3646 uint32_t timeout, uint32_t *pnn_list, int count)
3648 struct ctdb_disable_message disable = { 0 };
3649 struct disable_recoveries_state state;
3652 disable.pnn = ctdb->pnn;
3653 disable.srvid = next_srvid(ctdb);
3654 disable.timeout = timeout;
3656 state.pnn_list = pnn_list;
3657 state.node_count = count;
3660 state.reply = talloc_zero_array(mem_ctx, bool, count);
3661 if (state.reply == NULL) {
3665 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3667 disable_recoveries_handler,
3673 for (i=0; i<count; i++) {
3674 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3683 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3685 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3687 ret = (state.status >= 0 ? 0 : 1);
3691 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3692 disable.srvid, &state);
3696 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3697 int argc, const char **argv)
3699 struct ctdb_node_map *nodemap = NULL;
3700 struct ctdb_node_map *file_nodemap;
3701 struct ctdb_node_map *remote_nodemap;
3702 struct ctdb_req_control request;
3703 struct ctdb_reply_control **reply;
3709 nodemap = get_nodemap(ctdb, false);
3710 if (nodemap == NULL) {
3714 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3715 if (file_nodemap == NULL) {
3719 for (i=0; i<nodemap->num; i++) {
3720 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3724 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3725 nodemap->node[i].pnn, TIMEOUT(),
3729 "ERROR: Failed to get nodes file from node %u\n",
3730 nodemap->node[i].pnn);
3734 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3736 "ERROR: Nodes file on node %u differs"
3737 " from current node (%u)\n",
3738 nodemap->node[i].pnn, ctdb->pnn);
3743 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3749 fprintf(stderr, "No change in nodes file,"
3750 " skipping unnecessary reload\n");
3754 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3755 mem_ctx, &pnn_list);
3757 fprintf(stderr, "Memory allocation error\n");
3761 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3764 fprintf(stderr, "Failed to disable recoveries\n");
3768 ctdb_req_control_reload_nodes_file(&request);
3769 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3770 pnn_list, count, TIMEOUT(),
3771 &request, NULL, &reply);
3773 bool failed = false;
3775 for (i=0; i<count; i++) {
3776 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3779 "Node %u failed to reload nodes\n",
3786 "You MUST fix failed nodes manually!\n");
3790 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3792 fprintf(stderr, "Failed to enable recoveries\n");
3799 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3800 ctdb_sock_addr *addr, uint32_t pnn)
3802 struct ctdb_public_ip_list *pubip_list;
3803 struct ctdb_public_ip pubip;
3804 struct ctdb_node_map *nodemap;
3805 struct ctdb_req_control request;
3809 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3810 CTDB_BROADCAST_CONNECTED,
3811 2*options.timelimit);
3813 fprintf(stderr, "Failed to disable IP check\n");
3817 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3818 pnn, TIMEOUT(), false, &pubip_list);
3820 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3825 for (i=0; i<pubip_list->num; i++) {
3826 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3831 if (i == pubip_list->num) {
3832 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3833 pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
3837 nodemap = get_nodemap(ctdb, false);
3838 if (nodemap == NULL) {
3842 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3844 fprintf(stderr, "Memory allocation error\n");
3850 ctdb_req_control_release_ip(&request, &pubip);
3852 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3853 pnn_list, count, TIMEOUT(),
3854 &request, NULL, NULL);
3856 fprintf(stderr, "Failed to release IP on nodes\n");
3860 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3861 pnn, TIMEOUT(), &pubip);
3863 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3870 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3871 int argc, const char **argv)
3873 ctdb_sock_addr addr;
3875 int ret, retries = 0;
3881 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3882 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3886 pnn = strtoul(argv[1], NULL, 10);
3887 if (pnn == CTDB_UNKNOWN_PNN) {
3888 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3892 while (retries < 5) {
3893 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3903 fprintf(stderr, "Failed to move IP %s to node %u\n",
3911 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3916 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3917 CTDB_BROADCAST_CONNECTED, pnn);
3920 "Failed to ask recovery master to distribute IPs\n");
3927 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3928 int argc, const char **argv)
3930 ctdb_sock_addr addr;
3931 struct ctdb_public_ip_list *pubip_list;
3932 struct ctdb_addr_info addr_info;
3934 int ret, i, retries = 0;
3940 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3941 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3945 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3946 ctdb->cmd_pnn, TIMEOUT(),
3947 false, &pubip_list);
3949 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3954 for (i=0; i<pubip_list->num; i++) {
3955 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3956 fprintf(stderr, "Node already knows about IP %s\n",
3957 ctdb_sock_addr_to_string(mem_ctx, &addr));
3962 addr_info.addr = addr;
3963 addr_info.mask = mask;
3964 addr_info.iface = argv[1];
3966 while (retries < 5) {
3967 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3968 ctdb->cmd_pnn, TIMEOUT(),
3979 fprintf(stderr, "Failed to add public IP to node %u."
3980 " Giving up\n", ctdb->cmd_pnn);
3984 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3992 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3993 int argc, const char **argv)
3995 ctdb_sock_addr addr;
3996 struct ctdb_public_ip_list *pubip_list;
3997 struct ctdb_addr_info addr_info;
4004 if (! parse_ip(argv[0], NULL, 0, &addr)) {
4005 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
4009 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
4010 ctdb->cmd_pnn, TIMEOUT(),
4011 false, &pubip_list);
4013 fprintf(stderr, "Failed to get Public IPs from node %u\n",
4018 for (i=0; i<pubip_list->num; i++) {
4019 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
4024 if (i == pubip_list->num) {
4025 fprintf(stderr, "Node does not know about IP address %s\n",
4026 ctdb_sock_addr_to_string(mem_ctx, &addr));
4030 addr_info.addr = addr;
4032 addr_info.iface = NULL;
4034 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4035 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
4037 fprintf(stderr, "Failed to delete public IP from node %u\n",
4045 #define DB_VERSION 3
4046 #define MAX_DB_NAME 64
4047 #define MAX_REC_BUFFER_SIZE (100*1000)
4050 unsigned long version;
4052 unsigned long flags;
4055 char name[MAX_DB_NAME];
4058 struct backup_state {
4059 TALLOC_CTX *mem_ctx;
4060 struct ctdb_rec_buffer *recbuf;
4063 unsigned int nbuf, nrec;
4066 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4067 TDB_DATA key, TDB_DATA data, void *private_data)
4069 struct backup_state *state = (struct backup_state *)private_data;
4073 if (state->recbuf == NULL) {
4074 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4076 if (state->recbuf == NULL) {
4081 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4087 len = ctdb_rec_buffer_len(state->recbuf);
4088 if (len < MAX_REC_BUFFER_SIZE) {
4092 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4094 fprintf(stderr, "Failed to write records to backup file\n");
4099 state->nrec += state->recbuf->count;
4100 TALLOC_FREE(state->recbuf);
4105 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4106 int argc, const char **argv)
4108 const char *db_name;
4109 struct ctdb_db_context *db;
4112 struct backup_state state;
4113 struct db_header db_hdr;
4120 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4124 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4127 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4131 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4134 fprintf(stderr, "Failed to open file %s for writing\n",
4139 /* Write empty header first */
4140 ZERO_STRUCT(db_hdr);
4141 ret = write(fd, &db_hdr, sizeof(struct db_header));
4145 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4149 state.mem_ctx = mem_ctx;
4150 state.recbuf = NULL;
4155 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4157 fprintf(stderr, "Failed to collect records from DB %s\n",
4163 if (state.recbuf != NULL) {
4164 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4167 "Failed to write records to backup file\n");
4173 state.nrec += state.recbuf->count;
4174 TALLOC_FREE(state.recbuf);
4177 db_hdr.version = DB_VERSION;
4178 db_hdr.timestamp = time(NULL);
4179 db_hdr.flags = db_flags;
4180 db_hdr.nbuf = state.nbuf;
4181 db_hdr.nrec = state.nrec;
4182 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4184 lseek(fd, 0, SEEK_SET);
4185 ret = write(fd, &db_hdr, sizeof(struct db_header));
4189 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4194 printf("Database backed up to %s\n", argv[1]);
4198 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4199 int argc, const char **argv)
4201 const char *db_name = NULL;
4202 struct ctdb_db_context *db;
4203 struct db_header db_hdr;
4204 struct ctdb_node_map *nodemap;
4205 struct ctdb_req_control request;
4206 struct ctdb_reply_control **reply;
4207 struct ctdb_transdb wipedb;
4208 struct ctdb_pulldb_ext pulldb;
4209 struct ctdb_rec_buffer *recbuf;
4210 uint32_t generation;
4216 if (argc < 1 || argc > 2) {
4220 fd = open(argv[0], O_RDONLY, 0600);
4223 fprintf(stderr, "Failed to open file %s for reading\n",
4232 ret = read(fd, &db_hdr, sizeof(struct db_header));
4236 fprintf(stderr, "Failed to read db header from file %s\n",
4240 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4242 if (db_hdr.version != DB_VERSION) {
4244 "Wrong version of backup file, expected %u, got %lu\n",
4245 DB_VERSION, db_hdr.version);
4250 if (db_name == NULL) {
4251 db_name = db_hdr.name;
4254 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4255 localtime(&db_hdr.timestamp));
4256 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4258 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4261 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4266 nodemap = get_nodemap(ctdb, false);
4267 if (nodemap == NULL) {
4268 fprintf(stderr, "Failed to get nodemap\n");
4273 ret = get_generation(mem_ctx, ctdb, &generation);
4275 fprintf(stderr, "Failed to get current generation\n");
4280 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4287 wipedb.db_id = ctdb_db_id(db);
4288 wipedb.tid = generation;
4290 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4291 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4292 ctdb->client, pnn_list, count,
4293 TIMEOUT(), &request, NULL, NULL);
4299 ctdb_req_control_db_transaction_start(&request, &wipedb);
4300 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4301 pnn_list, count, TIMEOUT(),
4302 &request, NULL, NULL);
4307 ctdb_req_control_wipe_database(&request, &wipedb);
4308 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4309 pnn_list, count, TIMEOUT(),
4310 &request, NULL, NULL);
4315 pulldb.db_id = ctdb_db_id(db);
4317 pulldb.srvid = SRVID_CTDB_PUSHDB;
4319 ctdb_req_control_db_push_start(&request, &pulldb);
4320 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4321 pnn_list, count, TIMEOUT(),
4322 &request, NULL, NULL);
4327 for (i=0; i<db_hdr.nbuf; i++) {
4328 struct ctdb_req_message message;
4331 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4336 data.dsize = ctdb_rec_buffer_len(recbuf);
4337 data.dptr = talloc_size(mem_ctx, data.dsize);
4338 if (data.dptr == NULL) {
4342 ctdb_rec_buffer_push(recbuf, data.dptr);
4344 message.srvid = pulldb.srvid;
4345 message.data.data = data;
4347 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4355 talloc_free(recbuf);
4356 talloc_free(data.dptr);
4359 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4360 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4361 pnn_list, count, TIMEOUT(),
4362 &request, NULL, &reply);
4367 for (i=0; i<count; i++) {
4368 uint32_t num_records;
4370 ret = ctdb_reply_control_db_push_confirm(reply[i],
4373 fprintf(stderr, "Invalid response from node %u\n",
4378 if (num_records != db_hdr.nrec) {
4379 fprintf(stderr, "Node %u received %u of %lu records\n",
4380 pnn_list[i], num_records, db_hdr.nrec);
4385 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4386 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4387 pnn_list, count, TIMEOUT(),
4388 &request, NULL, NULL);
4393 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4394 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4395 pnn_list, count, TIMEOUT(),
4396 &request, NULL, NULL);
4401 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4402 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4403 ctdb->client, pnn_list, count,
4404 TIMEOUT(), &request, NULL, NULL);
4409 printf("Database %s restored\n", db_name);
4416 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4417 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4421 struct dumpdbbackup_state {
4422 ctdb_rec_parser_func_t parser;
4423 struct dump_record_state sub_state;
4426 static int dumpdbbackup_handler(uint32_t reqid,
4427 struct ctdb_ltdb_header *header,
4428 TDB_DATA key, TDB_DATA data,
4431 struct dumpdbbackup_state *state =
4432 (struct dumpdbbackup_state *)private_data;
4433 struct ctdb_ltdb_header hdr;
4436 ret = ctdb_ltdb_header_extract(&data, &hdr);
4441 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4444 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4445 int argc, const char **argv)
4447 struct db_header db_hdr;
4449 struct dumpdbbackup_state state;
4453 usage("dumpbackup");
4456 fd = open(argv[0], O_RDONLY, 0600);
4459 fprintf(stderr, "Failed to open file %s for reading\n",
4464 ret = read(fd, &db_hdr, sizeof(struct db_header));
4468 fprintf(stderr, "Failed to read db header from file %s\n",
4472 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4474 if (db_hdr.version != DB_VERSION) {
4476 "Wrong version of backup file, expected %u, got %lu\n",
4477 DB_VERSION, db_hdr.version);
4482 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4483 localtime(&db_hdr.timestamp));
4484 printf("Dumping database %s from backup @ %s\n",
4485 db_hdr.name, timebuf);
4487 state.parser = dump_record;
4488 state.sub_state.count = 0;
4490 for (i=0; i<db_hdr.nbuf; i++) {
4491 struct ctdb_rec_buffer *recbuf;
4493 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4495 fprintf(stderr, "Failed to read records\n");
4500 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4503 fprintf(stderr, "Failed to dump records\n");
4510 printf("Dumped %u record(s)\n", state.sub_state.count);
4514 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4515 int argc, const char **argv)
4517 const char *db_name;
4518 struct ctdb_db_context *db;
4521 struct ctdb_node_map *nodemap;
4522 struct ctdb_req_control request;
4523 struct ctdb_transdb wipedb;
4524 uint32_t generation;
4532 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4536 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4539 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4543 nodemap = get_nodemap(ctdb, false);
4544 if (nodemap == NULL) {
4545 fprintf(stderr, "Failed to get nodemap\n");
4549 ret = get_generation(mem_ctx, ctdb, &generation);
4551 fprintf(stderr, "Failed to get current generation\n");
4555 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4561 ctdb_req_control_db_freeze(&request, db_id);
4562 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4563 ctdb->client, pnn_list, count,
4564 TIMEOUT(), &request, NULL, NULL);
4569 wipedb.db_id = db_id;
4570 wipedb.tid = generation;
4572 ctdb_req_control_db_transaction_start(&request, &wipedb);
4573 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4574 pnn_list, count, TIMEOUT(),
4575 &request, NULL, NULL);
4580 ctdb_req_control_wipe_database(&request, &wipedb);
4581 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4582 pnn_list, count, TIMEOUT(),
4583 &request, NULL, NULL);
4588 ctdb_req_control_db_set_healthy(&request, db_id);
4589 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4590 pnn_list, count, TIMEOUT(),
4591 &request, NULL, NULL);
4596 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4597 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4598 pnn_list, count, TIMEOUT(),
4599 &request, NULL, NULL);
4604 ctdb_req_control_db_thaw(&request, db_id);
4605 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4606 ctdb->client, pnn_list, count,
4607 TIMEOUT(), &request, NULL, NULL);
4612 printf("Database %s wiped\n", db_name);
4617 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4618 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4622 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4623 int argc, const char **argv)
4628 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4629 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4634 printf("%u\n", recmaster);
4638 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4639 int argc, const char **argv)
4641 char *t, *event_helper = NULL;
4642 char *eventd_socket = NULL;
4643 const char **new_argv;
4646 t = getenv("CTDB_EVENT_HELPER");
4648 event_helper = talloc_strdup(mem_ctx, t);
4650 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb_event",
4651 CTDB_HELPER_BINDIR);
4654 if (event_helper == NULL) {
4655 fprintf(stderr, "Unable to set event daemon helper\n");
4659 t = getenv("CTDB_SOCKET");
4661 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4664 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4668 if (eventd_socket == NULL) {
4669 fprintf(stderr, "Unable to set event daemon socket\n");
4673 new_argv = talloc_array(mem_ctx, const char *, argc + 1);
4674 if (new_argv == NULL) {
4675 fprintf(stderr, "Memory allocation error\n");
4679 new_argv[0] = eventd_socket;
4680 for (i=0; i<argc; i++) {
4681 new_argv[i+1] = argv[i];
4684 return run_helper(mem_ctx, "event daemon helper", event_helper,
4688 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4689 int argc, const char **argv)
4691 const char *new_argv[3];
4694 usage("scriptstatus");
4697 new_argv[0] = "status";
4698 new_argv[1] = (argc == 0) ? "monitor" : argv[0];
4701 (void) control_event(mem_ctx, ctdb, 2, new_argv);
4705 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4706 int argc, const char **argv)
4708 char *t, *natgw_helper = NULL;
4714 t = getenv("CTDB_NATGW_HELPER");
4716 natgw_helper = talloc_strdup(mem_ctx, t);
4718 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4719 CTDB_HELPER_BINDIR);
4722 if (natgw_helper == NULL) {
4723 fprintf(stderr, "Unable to set NAT gateway helper\n");
4727 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4731 static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4732 int argc, const char **argv)
4734 char *t, *natgw_helper = NULL;
4735 const char *cmd_argv[] = { "natgwlist", NULL };
4741 t = getenv("CTDB_NATGW_HELPER");
4743 natgw_helper = talloc_strdup(mem_ctx, t);
4745 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4746 CTDB_HELPER_BINDIR);
4749 if (natgw_helper == NULL) {
4750 fprintf(stderr, "Unable to set NAT gateway helper\n");
4754 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4759 * Find the PNN of the current node
4760 * discover the pnn by loading the nodes file and try to bind
4761 * to all addresses one at a time until the ip address is found.
4763 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4765 struct ctdb_node_map *nodemap;
4768 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4769 if (nodemap == NULL) {
4773 for (i=0; i<nodemap->num; i++) {
4774 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4777 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4779 *pnn = nodemap->node[i].pnn;
4781 talloc_free(nodemap);
4786 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4787 talloc_free(nodemap);
4791 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4792 int argc, const char **argv)
4794 const char *reclock;
4798 usage("getreclock");
4801 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4802 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4807 if (reclock != NULL) {
4808 printf("%s\n", reclock);
4814 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4815 struct ctdb_context *ctdb,
4816 int argc, const char **argv)
4818 uint32_t lmasterrole = 0;
4822 usage("setlmasterrole");
4825 if (strcmp(argv[0], "on") == 0) {
4827 } else if (strcmp(argv[0], "off") == 0) {
4830 usage("setlmasterrole");
4833 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4834 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4842 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4843 struct ctdb_context *ctdb,
4844 int argc, const char **argv)
4846 uint32_t recmasterrole = 0;
4850 usage("setrecmasterrole");
4853 if (strcmp(argv[0], "on") == 0) {
4855 } else if (strcmp(argv[0], "off") == 0) {
4858 usage("setrecmasterrole");
4861 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4862 ctdb->cmd_pnn, TIMEOUT(),
4871 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4872 struct ctdb_context *ctdb,
4873 int argc, const char **argv)
4880 usage("setdbreadonly");
4883 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4887 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
4888 fprintf(stderr, "Cannot set READONLY on persistent DB\n");
4892 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4893 ctdb->cmd_pnn, TIMEOUT(), db_id);
4901 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4902 int argc, const char **argv)
4909 usage("setdbsticky");
4912 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4916 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
4917 fprintf(stderr, "Cannot set STICKY on persistent DB\n");
4921 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4922 ctdb->cmd_pnn, TIMEOUT(), db_id);
4930 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4931 int argc, const char **argv)
4933 const char *db_name;
4934 struct ctdb_db_context *db;
4935 struct ctdb_transaction_handle *h;
4940 if (argc < 2 || argc > 3) {
4944 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4948 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
4949 fprintf(stderr, "DB %s is not a persistent database\n",
4954 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4957 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4961 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4963 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4967 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4968 TIMEOUT(), db, true, &h);
4970 fprintf(stderr, "Failed to start transaction on db %s\n",
4975 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4977 fprintf(stderr, "Failed to read record for key %s\n",
4979 ctdb_transaction_cancel(h);
4983 printf("%.*s\n", (int)data.dsize, data.dptr);
4985 ctdb_transaction_cancel(h);
4989 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4990 int argc, const char **argv)
4992 const char *db_name;
4993 struct ctdb_db_context *db;
4994 struct ctdb_transaction_handle *h;
5003 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5007 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5008 fprintf(stderr, "DB %s is not a persistent database\n",
5013 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5016 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5020 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5022 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5026 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5028 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5032 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5033 TIMEOUT(), db, false, &h);
5035 fprintf(stderr, "Failed to start transaction on db %s\n",
5040 ret = ctdb_transaction_store_record(h, key, data);
5042 fprintf(stderr, "Failed to store record for key %s\n",
5044 ctdb_transaction_cancel(h);
5048 ret = ctdb_transaction_commit(h);
5050 fprintf(stderr, "Failed to commit transaction on db %s\n",
5052 ctdb_transaction_cancel(h);
5059 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5060 int argc, const char **argv)
5062 const char *db_name;
5063 struct ctdb_db_context *db;
5064 struct ctdb_transaction_handle *h;
5073 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5077 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5078 fprintf(stderr, "DB %s is not a persistent database\n",
5083 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5086 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5090 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5092 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5096 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5097 TIMEOUT(), db, false, &h);
5099 fprintf(stderr, "Failed to start transaction on db %s\n",
5104 ret = ctdb_transaction_delete_record(h, key);
5106 fprintf(stderr, "Failed to delete record for key %s\n",
5108 ctdb_transaction_cancel(h);
5112 ret = ctdb_transaction_commit(h);
5114 fprintf(stderr, "Failed to commit transaction on db %s\n",
5116 ctdb_transaction_cancel(h);
5123 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5131 /* Skip whitespace */
5132 n = strspn(*ptr, " \t");
5136 /* Quoted ASCII string - no wide characters! */
5138 n = strcspn(t, "\"");
5141 ret = str_to_data(t, n, mem_ctx, data);
5148 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5152 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5159 #define MAX_LINE_SIZE 1024
5161 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5162 TDB_DATA *key, TDB_DATA *value)
5164 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5168 ptr = fgets(line, MAX_LINE_SIZE, file);
5174 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5175 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5176 /* Line Ignored but not EOF */
5182 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5184 /* Line Ignored but not EOF */
5185 talloc_free(key->dptr);
5193 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5194 int argc, const char **argv)
5196 const char *db_name;
5197 struct ctdb_db_context *db;
5198 struct ctdb_transaction_handle *h;
5201 TDB_DATA key, value;
5204 if (argc < 1 || argc > 2) {
5208 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5212 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5213 fprintf(stderr, "DB %s is not a persistent database\n",
5219 file = fopen(argv[1], "r");
5221 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5228 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5231 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5235 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5236 TIMEOUT(), db, false, &h);
5238 fprintf(stderr, "Failed to start transaction on db %s\n",
5243 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5244 if (key.dsize != 0) {
5245 ret = ctdb_transaction_store_record(h, key, value);
5247 fprintf(stderr, "Failed to store record\n");
5248 ctdb_transaction_cancel(h);
5251 talloc_free(key.dptr);
5252 talloc_free(value.dptr);
5256 ret = ctdb_transaction_commit(h);
5258 fprintf(stderr, "Failed to commit transaction on db %s\n",
5260 ctdb_transaction_cancel(h);
5264 if (file != stdin) {
5270 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5271 int argc, const char **argv)
5273 struct tdb_context *tdb;
5275 struct ctdb_ltdb_header header;
5278 if (argc < 2 || argc > 3) {
5282 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5284 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5288 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5290 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5295 data = tdb_fetch(tdb, key);
5296 if (data.dptr == NULL) {
5297 fprintf(stderr, "No record for key %s\n", argv[1]);
5302 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5303 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5314 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5316 fprintf(stderr, "Failed to open output file %s\n",
5321 nwritten = sys_write(fd, data.dptr, data.dsize);
5322 if (nwritten != data.dsize) {
5323 fprintf(stderr, "Failed to write record to file\n");
5332 ret = ctdb_ltdb_header_extract(&data, &header);
5334 fprintf(stderr, "Failed to parse header from data\n");
5338 dump_ltdb_header(&header);
5339 dump_tdb_data("data", data);
5344 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5345 int argc, const char **argv)
5347 struct tdb_context *tdb;
5348 TDB_DATA key, data[2], value;
5349 struct ctdb_ltdb_header header;
5350 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5353 if (argc < 3 || argc > 5) {
5357 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5359 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5363 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5365 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5370 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5372 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5377 ZERO_STRUCT(header);
5380 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5383 header.dmaster = (uint32_t)atol(argv[4]);
5386 header.flags = (uint32_t)atol(argv[5]);
5389 ctdb_ltdb_header_push(&header, header_buf);
5391 data[0].dsize = ctdb_ltdb_header_len(&header);
5392 data[0].dptr = header_buf;
5394 data[1].dsize = value.dsize;
5395 data[1].dptr = value.dptr;
5397 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5399 fprintf(stderr, "Failed to write record %s to file %s\n",
5408 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5409 int argc, const char **argv)
5411 const char *db_name;
5412 struct ctdb_db_context *db;
5413 struct ctdb_record_handle *h;
5416 bool readonly = false;
5419 if (argc < 2 || argc > 3) {
5424 if (strcmp(argv[2], "readonly") == 0) {
5431 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5435 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5436 fprintf(stderr, "DB %s is not a volatile database\n",
5441 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5444 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5448 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5450 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5454 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5455 db, key, readonly, &h, NULL, &data);
5457 fprintf(stderr, "Failed to read record for key %s\n",
5460 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5461 (int)data.dsize, data.dptr);
5468 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5469 int argc, const char **argv)
5471 const char *db_name;
5472 struct ctdb_db_context *db;
5473 struct ctdb_record_handle *h;
5482 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5486 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5487 fprintf(stderr, "DB %s is not a volatile database\n",
5492 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5495 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5499 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5501 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5505 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5507 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5511 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5512 db, key, false, &h, NULL, NULL);
5514 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5518 ret = ctdb_store_record(h, data);
5520 fprintf(stderr, "Failed to store record for key %s\n",
5528 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5529 int argc, const char **argv)
5531 const char *db_name;
5532 struct ctdb_db_context *db;
5533 struct ctdb_record_handle *h;
5542 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5546 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5547 fprintf(stderr, "DB %s is not a volatile database\n",
5552 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5555 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5559 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5561 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5565 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5566 db, key, false, &h, NULL, &data);
5568 fprintf(stderr, "Failed to fetch record for key %s\n",
5573 ret = ctdb_delete_record(h);
5575 fprintf(stderr, "Failed to delete record for key %s\n",
5583 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5584 int argc, const char **argv)
5586 struct sockaddr_in sin;
5592 usage("chktcpport");
5595 port = atoi(argv[0]);
5597 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5599 fprintf(stderr, "Failed to open local socket\n");
5603 v = fcntl(s, F_GETFL, 0);
5604 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5605 fprintf(stderr, "Unable to set socket non-blocking\n");
5610 bzero(&sin, sizeof(sin));
5611 sin.sin_family = AF_INET;
5612 sin.sin_port = htons(port);
5613 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5616 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5623 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5624 int argc, const char **argv)
5627 const char *db_name;
5632 usage("getdbseqnum");
5635 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5639 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5640 ctdb->cmd_pnn, TIMEOUT(), db_id,
5643 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5648 printf("0x%"PRIx64"\n", seqnum);
5652 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5653 int argc, const char **argv)
5655 const char *nodestring = NULL;
5656 struct ctdb_node_map *nodemap;
5658 bool print_hdr = false;
5661 usage("nodestatus");
5665 nodestring = argv[0];
5666 if (strcmp(nodestring, "all") == 0) {
5671 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5675 if (options.machinereadable) {
5676 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5678 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5682 for (i=0; i<nodemap->num; i++) {
5683 ret |= nodemap->node[i].flags;
5692 } db_stats_fields[] = {
5693 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5694 DBSTATISTICS_FIELD(db_ro_delegations),
5695 DBSTATISTICS_FIELD(db_ro_revokes),
5696 DBSTATISTICS_FIELD(locks.num_calls),
5697 DBSTATISTICS_FIELD(locks.num_current),
5698 DBSTATISTICS_FIELD(locks.num_pending),
5699 DBSTATISTICS_FIELD(locks.num_failed),
5700 DBSTATISTICS_FIELD(db_ro_delegations),
5703 static void print_dbstatistics(const char *db_name,
5704 struct ctdb_db_statistics *s)
5707 const char *prefix = NULL;
5710 printf("DB Statistics %s\n", db_name);
5712 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5713 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5714 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5716 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5717 prefix = db_stats_fields[i].name;
5718 printf(" %*.*s\n", preflen-1, preflen-1,
5719 db_stats_fields[i].name);
5724 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5725 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5726 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5729 printf(" hop_count_buckets:");
5730 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5731 printf(" %d", s->hop_count_bucket[i]);
5735 printf(" lock_buckets:");
5736 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5737 printf(" %d", s->locks.buckets[i]);
5741 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5742 "locks_latency MIN/AVG/MAX",
5743 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5744 s->locks.latency.max, s->locks.latency.num);
5746 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5747 "vacuum_latency MIN/AVG/MAX",
5748 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5749 s->vacuum.latency.max, s->vacuum.latency.num);
5751 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5752 for (i=0; i<s->num_hot_keys; i++) {
5754 printf(" Count:%d Key:", s->hot_keys[i].count);
5755 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5756 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5762 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5763 int argc, const char **argv)
5766 const char *db_name;
5767 struct ctdb_db_statistics *dbstats;
5771 usage("dbstatistics");
5774 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5778 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5779 ctdb->cmd_pnn, TIMEOUT(), db_id,
5782 fprintf(stderr, "Failed to get statistics for DB %s\n",
5787 print_dbstatistics(db_name, dbstats);
5791 struct disable_takeover_runs_state {
5799 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5802 struct disable_takeover_runs_state *state =
5803 (struct disable_takeover_runs_state *)private_data;
5806 if (data.dsize != sizeof(int)) {
5811 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5812 ret = *(int *)data.dptr;
5814 state->status = ret;
5818 for (i=0; i<state->node_count; i++) {
5819 if (state->pnn_list[i] == ret) {
5820 state->reply[i] = true;
5826 for (i=0; i<state->node_count; i++) {
5827 if (! state->reply[i]) {
5828 state->done = false;
5834 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5835 struct ctdb_context *ctdb, uint32_t timeout,
5836 uint32_t *pnn_list, int count)
5838 struct ctdb_disable_message disable = { 0 };
5839 struct disable_takeover_runs_state state;
5842 disable.pnn = ctdb->pnn;
5843 disable.srvid = next_srvid(ctdb);
5844 disable.timeout = timeout;
5846 state.pnn_list = pnn_list;
5847 state.node_count = count;
5850 state.reply = talloc_zero_array(mem_ctx, bool, count);
5851 if (state.reply == NULL) {
5855 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5857 disable_takeover_run_handler,
5863 for (i=0; i<count; i++) {
5864 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5873 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5875 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5877 ret = (state.status >= 0 ? 0 : 1);
5881 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5882 disable.srvid, &state);
5886 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5887 int argc, const char **argv)
5889 const char *nodestring = NULL;
5890 struct ctdb_node_map *nodemap, *nodemap2;
5891 struct ctdb_req_control request;
5892 uint32_t *pnn_list, *pnn_list2;
5893 int ret, count, count2;
5900 nodestring = argv[0];
5903 nodemap = get_nodemap(ctdb, false);
5904 if (nodemap == NULL) {
5908 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5912 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5913 mem_ctx, &pnn_list);
5915 fprintf(stderr, "Memory allocation error\n");
5919 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5920 mem_ctx, &pnn_list2);
5922 fprintf(stderr, "Memory allocation error\n");
5926 /* Disable takeover runs on all connected nodes. A reply
5927 * indicating success is needed from each node so all nodes
5928 * will need to be active.
5930 * A check could be added to not allow reloading of IPs when
5931 * there are disconnected nodes. However, this should
5932 * probably be left up to the administrator.
5934 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5937 fprintf(stderr, "Failed to disable takeover runs\n");
5941 /* Now tell all the desired nodes to reload their public IPs.
5942 * Keep trying this until it succeeds. This assumes all
5943 * failures are transient, which might not be true...
5945 ctdb_req_control_reload_public_ips(&request);
5946 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5947 pnn_list2, count2, TIMEOUT(),
5948 &request, NULL, NULL);
5950 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5953 /* It isn't strictly necessary to wait until takeover runs are
5954 * re-enabled but doing so can't hurt.
5956 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5958 fprintf(stderr, "Failed to enable takeover runs\n");
5962 return ipreallocate(mem_ctx, ctdb);
5965 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5966 int argc, const char **argv)
5968 ctdb_sock_addr addr;
5975 if (! parse_ip(argv[0], NULL, 0, &addr)) {
5976 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
5980 iface = ctdb_sys_find_ifname(&addr);
5981 if (iface == NULL) {
5982 fprintf(stderr, "Failed to find interface for IP %s\n",
5992 static const struct ctdb_cmd {
5994 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5995 bool without_daemon; /* can be run without daemon running ? */
5996 bool remote; /* can be run on remote nodes */
5999 } ctdb_commands[] = {
6000 { "version", control_version, true, false,
6001 "show version of ctdb", NULL },
6002 { "status", control_status, false, true,
6003 "show node status", NULL },
6004 { "uptime", control_uptime, false, true,
6005 "show node uptime", NULL },
6006 { "ping", control_ping, false, true,
6007 "ping all nodes", NULL },
6008 { "runstate", control_runstate, false, true,
6009 "get/check runstate of a node",
6010 "[setup|first_recovery|startup|running]" },
6011 { "getvar", control_getvar, false, true,
6012 "get a tunable variable", "<name>" },
6013 { "setvar", control_setvar, false, true,
6014 "set a tunable variable", "<name> <value>" },
6015 { "listvars", control_listvars, false, true,
6016 "list tunable variables", NULL },
6017 { "statistics", control_statistics, false, true,
6018 "show ctdb statistics", NULL },
6019 { "statisticsreset", control_statistics_reset, false, true,
6020 "reset ctdb statistics", NULL },
6021 { "stats", control_stats, false, true,
6022 "show rolling statistics", "[count]" },
6023 { "ip", control_ip, false, true,
6024 "show public ips", "[all]" },
6025 { "ipinfo", control_ipinfo, false, true,
6026 "show public ip details", "<ip>" },
6027 { "ifaces", control_ifaces, false, true,
6028 "show interfaces", NULL },
6029 { "setifacelink", control_setifacelink, false, true,
6030 "set interface link status", "<iface> up|down" },
6031 { "process-exists", control_process_exists, false, true,
6032 "check if a process exists on a node", "<pid>" },
6033 { "getdbmap", control_getdbmap, false, true,
6034 "show attached databases", NULL },
6035 { "getdbstatus", control_getdbstatus, false, true,
6036 "show database status", "<dbname|dbid>" },
6037 { "catdb", control_catdb, false, false,
6038 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6039 { "cattdb", control_cattdb, false, false,
6040 "dump local ctdb database", "<dbname|dbid>" },
6041 { "getmonmode", control_getmonmode, false, true,
6042 "show monitoring mode", NULL },
6043 { "getcapabilities", control_getcapabilities, false, true,
6044 "show node capabilities", NULL },
6045 { "pnn", control_pnn, false, false,
6046 "show the pnn of the currnet node", NULL },
6047 { "lvs", control_lvs, false, false,
6048 "show lvs configuration", "master|list|status" },
6049 { "disablemonitor", control_disable_monitor, false, true,
6050 "disable monitoring", NULL },
6051 { "enablemonitor", control_enable_monitor, false, true,
6052 "enable monitoring", NULL },
6053 { "setdebug", control_setdebug, false, true,
6054 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6055 { "getdebug", control_getdebug, false, true,
6056 "get debug level", NULL },
6057 { "attach", control_attach, false, false,
6058 "attach a database", "<dbname> [persistent]" },
6059 { "detach", control_detach, false, false,
6060 "detach database(s)", "<dbname|dbid> ..." },
6061 { "dumpmemory", control_dumpmemory, false, true,
6062 "dump ctdbd memory map", NULL },
6063 { "rddumpmemory", control_rddumpmemory, false, true,
6064 "dump recoverd memory map", NULL },
6065 { "getpid", control_getpid, false, true,
6066 "get ctdbd process ID", NULL },
6067 { "disable", control_disable, false, true,
6068 "disable a node", NULL },
6069 { "enable", control_enable, false, true,
6070 "enable a node", NULL },
6071 { "stop", control_stop, false, true,
6072 "stop a node", NULL },
6073 { "continue", control_continue, false, true,
6074 "continue a stopped node", NULL },
6075 { "ban", control_ban, false, true,
6076 "ban a node", "<bantime>"},
6077 { "unban", control_unban, false, true,
6078 "unban a node", NULL },
6079 { "shutdown", control_shutdown, false, true,
6080 "shutdown ctdb daemon", NULL },
6081 { "recover", control_recover, false, true,
6082 "force recovery", NULL },
6083 { "sync", control_ipreallocate, false, true,
6084 "run ip reallocation (deprecated)", NULL },
6085 { "ipreallocate", control_ipreallocate, false, true,
6086 "run ip reallocation", NULL },
6087 { "isnotrecmaster", control_isnotrecmaster, false, false,
6088 "check if local node is the recmaster", NULL },
6089 { "gratarp", control_gratarp, false, true,
6090 "send a gratuitous arp", "<ip> <interface>" },
6091 { "tickle", control_tickle, true, false,
6092 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6093 { "gettickles", control_gettickles, false, true,
6094 "get the list of tickles", "<ip> [<port>]" },
6095 { "addtickle", control_addtickle, false, true,
6096 "add a tickle", "<ip>:<port> <ip>:<port>" },
6097 { "deltickle", control_deltickle, false, true,
6098 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6099 { "check_srvids", control_check_srvids, false, true,
6100 "check if srvid is registered", "<id> [<id> ...]" },
6101 { "listnodes", control_listnodes, true, true,
6102 "list nodes in the cluster", NULL },
6103 { "reloadnodes", control_reloadnodes, false, false,
6104 "reload the nodes file all nodes", NULL },
6105 { "moveip", control_moveip, false, false,
6106 "move an ip address to another node", "<ip> <node>" },
6107 { "addip", control_addip, false, true,
6108 "add an ip address to a node", "<ip/mask> <iface>" },
6109 { "delip", control_delip, false, true,
6110 "delete an ip address from a node", "<ip>" },
6111 { "backupdb", control_backupdb, false, false,
6112 "backup a database into a file", "<dbname|dbid> <file>" },
6113 { "restoredb", control_restoredb, false, false,
6114 "restore a database from a file", "<file> [dbname]" },
6115 { "dumpdbbackup", control_dumpdbbackup, true, false,
6116 "dump database from a backup file", "<file>" },
6117 { "wipedb", control_wipedb, false, false,
6118 "wipe the contents of a database.", "<dbname|dbid>"},
6119 { "recmaster", control_recmaster, false, true,
6120 "show the pnn for the recovery master", NULL },
6121 { "event", control_event, true, false,
6122 "event and event script commands", NULL },
6123 { "scriptstatus", control_scriptstatus, true, false,
6124 "show event script status",
6125 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6126 { "natgw", control_natgw, false, false,
6127 "show natgw configuration", "master|list|status" },
6128 { "natgwlist", control_natgwlist, false, false,
6129 "show the nodes belonging to this natgw configuration", NULL },
6130 { "getreclock", control_getreclock, false, true,
6131 "get recovery lock file", NULL },
6132 { "setlmasterrole", control_setlmasterrole, false, true,
6133 "set LMASTER role", "on|off" },
6134 { "setrecmasterrole", control_setrecmasterrole, false, true,
6135 "set RECMASTER role", "on|off"},
6136 { "setdbreadonly", control_setdbreadonly, false, true,
6137 "enable readonly records", "<dbname|dbid>" },
6138 { "setdbsticky", control_setdbsticky, false, true,
6139 "enable sticky records", "<dbname|dbid>"},
6140 { "pfetch", control_pfetch, false, false,
6141 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6142 { "pstore", control_pstore, false, false,
6143 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6144 { "pdelete", control_pdelete, false, false,
6145 "delete record from persistent database", "<dbname|dbid> <key>" },
6146 { "ptrans", control_ptrans, false, false,
6147 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6148 { "tfetch", control_tfetch, false, true,
6149 "fetch a record", "<tdb-file> <key> [<file>]" },
6150 { "tstore", control_tstore, false, true,
6151 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6152 { "readkey", control_readkey, false, false,
6153 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6154 { "writekey", control_writekey, false, false,
6155 "write value for a database key", "<dbname|dbid> <key> <value>" },
6156 { "deletekey", control_deletekey, false, false,
6157 "delete a database key", "<dbname|dbid> <key>" },
6158 { "checktcpport", control_checktcpport, true, false,
6159 "check if a service is bound to a specific tcp port or not", "<port>" },
6160 { "getdbseqnum", control_getdbseqnum, false, false,
6161 "get database sequence number", "<dbname|dbid>" },
6162 { "nodestatus", control_nodestatus, false, true,
6163 "show and return node status", "[all|<pnn-list>]" },
6164 { "dbstatistics", control_dbstatistics, false, true,
6165 "show database statistics", "<dbname|dbid>" },
6166 { "reloadips", control_reloadips, false, false,
6167 "reload the public addresses file", "[all|<pnn-list>]" },
6168 { "ipiface", control_ipiface, true, false,
6169 "Find the interface an ip address is hosted on", "<ip>" },
6172 static const struct ctdb_cmd *match_command(const char *command)
6174 const struct ctdb_cmd *cmd;
6177 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6178 cmd = &ctdb_commands[i];
6179 if (strlen(command) == strlen(cmd->name) &&
6180 strncmp(command, cmd->name, strlen(command)) == 0) {
6190 * Show usage message
6192 static void usage_full(void)
6196 poptPrintHelp(pc, stdout, 0);
6197 printf("\nCommands:\n");
6198 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6199 printf(" %-15s %-27s %s\n",
6200 ctdb_commands[i].name,
6201 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6202 ctdb_commands[i].msg);
6206 static void usage(const char *command)
6208 const struct ctdb_cmd *cmd;
6210 if (command == NULL) {
6215 cmd = match_command(command);
6219 poptPrintUsage(pc, stdout, 0);
6220 printf("\nCommands:\n");
6221 printf(" %-15s %-27s %s\n",
6222 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6228 struct poptOption cmdline_options[] = {
6230 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6231 "CTDB socket path", "filename" },
6232 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6234 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6235 "timelimit (in seconds)" },
6236 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6237 "node specification - integer" },
6238 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6239 "enable machine readable output", NULL },
6240 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6241 "specify separator for machine readable output", "CHAR" },
6242 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6243 "enable machine parsable output with separator |", NULL },
6244 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6245 "enable verbose output", NULL },
6246 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6247 "die if runtime exceeds this limit (in seconds)" },
6251 static int process_command(const struct ctdb_cmd *cmd, int argc,
6254 TALLOC_CTX *tmp_ctx;
6255 struct ctdb_context *ctdb;
6258 uint64_t srvid_offset;
6260 tmp_ctx = talloc_new(NULL);
6261 if (tmp_ctx == NULL) {
6262 fprintf(stderr, "Memory allocation error\n");
6266 if (cmd->without_daemon) {
6267 if (options.pnn != -1) {
6269 "Cannot specify node for command %s\n",
6274 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6275 talloc_free(tmp_ctx);
6279 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6281 fprintf(stderr, "Memory allocation error\n");
6285 ctdb->ev = tevent_context_init(ctdb);
6286 if (ctdb->ev == NULL) {
6287 fprintf(stderr, "Failed to initialize tevent\n");
6291 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6293 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6296 if (!find_node_xpnn(ctdb, NULL)) {
6297 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6302 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6303 srvid_offset = getpid() & 0xFFFF;
6304 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6306 if (options.pnn != -1) {
6307 status = verify_pnn(ctdb, options.pnn);
6312 ctdb->cmd_pnn = options.pnn;
6314 ctdb->cmd_pnn = ctdb->pnn;
6317 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6318 fprintf(stderr, "Node cannot be specified for command %s\n",
6323 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6324 talloc_free(tmp_ctx);
6328 talloc_free(tmp_ctx);
6332 static void signal_handler(int sig)
6334 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6337 static void alarm_handler(int sig)
6339 /* Kill any child processes */
6340 signal(SIGTERM, signal_handler);
6346 int main(int argc, const char *argv[])
6349 const char **extra_argv;
6351 const struct ctdb_cmd *cmd;
6352 const char *ctdb_socket;
6358 /* Set default options */
6359 options.socket = CTDB_SOCKET;
6360 options.debuglevelstr = NULL;
6361 options.timelimit = 10;
6363 options.maxruntime = 0;
6366 ctdb_socket = getenv("CTDB_SOCKET");
6367 if (ctdb_socket != NULL) {
6368 options.socket = ctdb_socket;
6371 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6372 POPT_CONTEXT_KEEP_FIRST);
6373 while ((opt = poptGetNextOpt(pc)) != -1) {
6374 fprintf(stderr, "Invalid option %s: %s\n",
6375 poptBadOption(pc, 0), poptStrerror(opt));
6379 if (options.maxruntime == 0) {
6380 const char *ctdb_timeout;
6382 ctdb_timeout = getenv("CTDB_TIMEOUT");
6383 if (ctdb_timeout != NULL) {
6384 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6386 options.maxruntime = 120;
6389 if (options.maxruntime <= 120) {
6390 /* default timeout is 120 seconds */
6391 options.maxruntime = 120;
6394 if (options.machineparsable) {
6395 options.machinereadable = 1;
6398 /* setup the remaining options for the commands */
6400 extra_argv = poptGetArgs(pc);
6403 while (extra_argv[extra_argc]) extra_argc++;
6406 if (extra_argc < 1) {
6410 cmd = match_command(extra_argv[0]);
6412 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6416 /* Enable logging */
6417 setup_logging("ctdb", DEBUG_STDERR);
6418 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6419 DEBUGLEVEL = loglevel;
6421 DEBUGLEVEL = DEBUG_ERR;
6424 signal(SIGALRM, alarm_handler);
6425 alarm(options.maxruntime);
6427 ret = process_command(cmd, extra_argc, extra_argv);
6432 (void)poptFreeContext(pc);