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 "protocol/protocol_util.h"
43 #include "common/system.h"
44 #include "client/client.h"
45 #include "client/client_sync.h"
47 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
49 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
50 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
54 const char *debuglevelstr;
62 int printemptyrecords;
69 static poptContext pc;
72 struct tevent_context *ev;
73 struct ctdb_client_context *client;
74 struct ctdb_node_map *nodemap;
75 uint32_t pnn, cmd_pnn;
79 static void usage(const char *command);
85 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
87 return (tv2->tv_sec - tv->tv_sec) +
88 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
91 static struct ctdb_node_and_flags *get_node_by_pnn(
92 struct ctdb_node_map *nodemap,
97 for (i=0; i<nodemap->num; i++) {
98 if (nodemap->node[i].pnn == pnn) {
99 return &nodemap->node[i];
105 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
107 static const struct {
111 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
112 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
113 { NODE_FLAGS_BANNED, "BANNED" },
114 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
115 { NODE_FLAGS_DELETED, "DELETED" },
116 { NODE_FLAGS_STOPPED, "STOPPED" },
117 { NODE_FLAGS_INACTIVE, "INACTIVE" },
119 char *flags_str = NULL;
122 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
123 if (flags & flag_names[i].flag) {
124 if (flags_str == NULL) {
125 flags_str = talloc_asprintf(mem_ctx,
126 "%s", flag_names[i].name);
128 flags_str = talloc_asprintf_append(flags_str,
129 "|%s", flag_names[i].name);
131 if (flags_str == NULL) {
132 return "OUT-OF-MEMORY";
136 if (flags_str == NULL) {
143 static uint64_t next_srvid(struct ctdb_context *ctdb)
150 * Get consistent nodemap information.
152 * If nodemap is already cached, use that. If not get it.
153 * If the current node is BANNED, then get nodemap from "better" node.
155 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
158 struct ctdb_node_map *nodemap;
159 struct ctdb_node_and_flags *node;
160 uint32_t current_node;
164 TALLOC_FREE(ctdb->nodemap);
167 if (ctdb->nodemap != NULL) {
168 return ctdb->nodemap;
171 tmp_ctx = talloc_new(ctdb);
172 if (tmp_ctx == NULL) {
176 current_node = ctdb->pnn;
178 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
179 current_node, TIMEOUT(), &nodemap);
181 fprintf(stderr, "Failed to get nodemap from node %u\n",
186 node = get_node_by_pnn(nodemap, current_node);
187 if (node->flags & NODE_FLAGS_BANNED) {
190 current_node = (current_node + 1) % nodemap->num;
191 node = get_node_by_pnn(nodemap, current_node);
193 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
196 } while (current_node != ctdb->pnn);
198 if (current_node == ctdb->pnn) {
199 /* Tried all nodes in the cluster */
200 fprintf(stderr, "Warning: All nodes are banned.\n");
207 ctdb->nodemap = talloc_steal(ctdb, nodemap);
211 talloc_free(tmp_ctx);
215 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
217 struct ctdb_node_map *nodemap;
225 nodemap = get_nodemap(ctdb, false);
226 if (nodemap == NULL) {
231 for (i=0; i<nodemap->num; i++) {
232 if (nodemap->node[i].pnn == pnn) {
238 fprintf(stderr, "Node %u does not exist\n", pnn);
242 if (nodemap->node[i].flags &
243 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
244 fprintf(stderr, "Node %u has status %s\n", pnn,
245 pretty_print_flags(ctdb, nodemap->node[i].flags));
252 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
253 struct ctdb_node_map *nodemap)
255 struct ctdb_node_map *nodemap2;
257 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
258 if (nodemap2 == NULL) {
262 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
264 if (nodemap2->node == NULL) {
265 talloc_free(nodemap2);
273 * Get the number and the list of matching nodes
275 * nodestring := NULL | all | pnn,[pnn,...]
277 * If nodestring is NULL, use the current node.
279 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
280 const char *nodestring,
281 struct ctdb_node_map **out)
283 struct ctdb_node_map *nodemap, *nodemap2;
284 struct ctdb_node_and_flags *node;
287 nodemap = get_nodemap(ctdb, false);
288 if (nodemap == NULL) {
292 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
293 if (nodemap2 == NULL) {
297 if (nodestring == NULL) {
298 for (i=0; i<nodemap->num; i++) {
299 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
300 nodemap2->node[0] = nodemap->node[i];
309 if (strcmp(nodestring, "all") == 0) {
310 for (i=0; i<nodemap->num; i++) {
311 nodemap2->node[i] = nodemap->node[i];
313 nodemap2->num = nodemap->num;
319 ns = talloc_strdup(mem_ctx, nodestring);
324 tok = strtok(ns, ",");
325 while (tok != NULL) {
329 pnn = (uint32_t)strtoul(tok, &endptr, 0);
330 if (pnn == 0 && tok == endptr) {
331 fprintf(stderr, "Invalid node %s\n", tok);
335 node = get_node_by_pnn(nodemap, pnn);
337 fprintf(stderr, "Node %u does not exist\n",
342 nodemap2->node[nodemap2->num] = *node;
345 tok = strtok(NULL, ",");
354 /* Compare IP address */
355 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
359 if (ip1->sa.sa_family != ip2->sa.sa_family) {
363 switch (ip1->sa.sa_family) {
365 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
366 sizeof(struct in_addr)) == 0);
370 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
371 sizeof(struct in6_addr)) == 0);
378 /* Append a node to a node map with given address and flags */
379 static bool node_map_add(struct ctdb_node_map *nodemap,
380 const char *nstr, uint32_t flags)
384 struct ctdb_node_and_flags *n;
386 if (! parse_ip(nstr, NULL, 0, &addr)) {
387 fprintf(stderr, "Invalid IP address %s\n", nstr);
392 nodemap->node = talloc_realloc(nodemap, nodemap->node,
393 struct ctdb_node_and_flags, num+1);
394 if (nodemap->node == NULL) {
398 n = &nodemap->node[num];
403 nodemap->num = num+1;
407 /* Read a nodes file into a node map */
408 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
414 struct ctdb_node_map *nodemap;
416 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
417 if (nodemap == NULL) {
421 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
426 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
430 for (i=0; i<nlines; i++) {
436 /* strip leading spaces */
437 while((*node == ' ') || (*node == '\t')) {
443 /* strip trailing spaces */
445 ((node[len-1] == ' ') || (node[len-1] == '\t')))
455 /* A "deleted" node is a node that is
456 commented out in the nodes file. This is
457 used instead of removing a line, which
458 would cause subsequent nodes to change
460 flags = NODE_FLAGS_DELETED;
461 node = discard_const("0.0.0.0");
465 if (! node_map_add(nodemap, node, flags)) {
467 TALLOC_FREE(nodemap);
476 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
478 struct ctdb_node_map *nodemap;
480 const char *nodes_list = NULL;
482 if (pnn != CTDB_UNKNOWN_PNN) {
483 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
484 if (nodepath != NULL) {
485 nodes_list = getenv(nodepath);
488 if (nodes_list == NULL) {
489 nodes_list = getenv("CTDB_NODES");
491 if (nodes_list == NULL) {
492 const char *basedir = getenv("CTDB_BASE");
493 if (basedir == NULL) {
494 basedir = CTDB_ETCDIR;
496 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
497 if (nodes_list == NULL) {
498 fprintf(stderr, "Memory allocation error\n");
503 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
504 if (nodemap == NULL) {
505 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
513 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
514 struct ctdb_context *ctdb,
515 struct ctdb_dbid_map *dbmap,
518 struct ctdb_dbid *db = NULL;
522 for (i=0; i<dbmap->num; i++) {
523 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
524 ctdb->pnn, TIMEOUT(),
525 dbmap->dbs[i].db_id, &name);
530 if (strcmp(db_name, name) == 0) {
531 talloc_free(discard_const(name));
540 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
541 const char *db_arg, uint32_t *db_id,
542 const char **db_name, uint8_t *db_flags)
544 struct ctdb_dbid_map *dbmap;
545 struct ctdb_dbid *db = NULL;
547 const char *name = NULL;
550 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
551 ctdb->pnn, TIMEOUT(), &dbmap);
556 if (strncmp(db_arg, "0x", 2) == 0) {
557 id = strtoul(db_arg, NULL, 0);
558 for (i=0; i<dbmap->num; i++) {
559 if (id == dbmap->dbs[i].db_id) {
566 db = db_find(mem_ctx, ctdb, dbmap, name);
570 fprintf(stderr, "No database matching '%s' found\n", db_arg);
575 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
576 ctdb->pnn, TIMEOUT(), id, &name);
585 if (db_name != NULL) {
586 *db_name = talloc_strdup(mem_ctx, name);
588 if (db_flags != NULL) {
589 *db_flags = db->flags;
594 static int h2i(char h)
596 if (h >= 'a' && h <= 'f') {
599 if (h >= 'A' && h <= 'F') {
605 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
612 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
617 data.dsize = len / 2;
618 data.dptr = talloc_size(mem_ctx, data.dsize);
619 if (data.dptr == NULL) {
623 for (i=0; i<data.dsize; i++) {
624 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
631 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
637 if (strncmp(str, "0x", 2) == 0) {
638 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
640 data.dptr = talloc_memdup(mem_ctx, str, len);
641 if (data.dptr == NULL) {
651 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
652 const char *path, int argc, const char **argv)
655 int save_errno, status, ret;
656 const char **new_argv;
659 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
660 if (new_argv == NULL) {
665 for (i=0; i<argc; i++) {
666 new_argv[i+1] = argv[i];
668 new_argv[argc+1] = NULL;
673 talloc_free(new_argv);
674 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
675 command, path, strerror(save_errno));
680 ret = execv(path, discard_const(new_argv));
684 /* Should not happen */
688 talloc_free(new_argv);
690 ret = waitpid(pid, &status, 0);
693 fprintf(stderr, "waitpid() failed for %s - %s\n",
694 command, strerror(save_errno));
698 if (WIFEXITED(status)) {
699 int pstatus = WEXITSTATUS(status);
700 if (WIFSIGNALED(status)) {
701 fprintf(stderr, "%s terminated with signal %d\n",
702 command, WTERMSIG(status));
704 } else if (pstatus >= 64 && pstatus < 255) {
705 fprintf(stderr, "%s failed with error %d\n",
706 command, pstatus-64);
712 } else if (WIFSIGNALED(status)) {
713 fprintf(stderr, "%s terminated with signal %d\n",
714 command, WTERMSIG(status));
725 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
726 int argc, const char **argv)
728 printf("%s\n", CTDB_VERSION_STRING);
732 static bool partially_online(TALLOC_CTX *mem_ctx,
733 struct ctdb_context *ctdb,
734 struct ctdb_node_and_flags *node)
736 struct ctdb_iface_list *iface_list;
740 if (node->flags != 0) {
744 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
745 node->pnn, TIMEOUT(), &iface_list);
751 for (i=0; i < iface_list->num; i++) {
752 if (iface_list->iface[i].link_state == 0) {
761 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
762 struct ctdb_context *ctdb,
763 struct ctdb_node_map *nodemap,
766 struct ctdb_node_and_flags *node;
769 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
773 "Disconnected", options.sep,
774 "Banned", options.sep,
775 "Disabled", options.sep,
776 "Unhealthy", options.sep,
777 "Stopped", options.sep,
778 "Inactive", options.sep,
779 "PartiallyOnline", options.sep,
780 "ThisNode", options.sep);
782 for (i=0; i<nodemap->num; i++) {
783 node = &nodemap->node[i];
784 if (node->flags & NODE_FLAGS_DELETED) {
788 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
790 node->pnn, options.sep,
791 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
793 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
794 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
795 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
797 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
798 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
799 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
800 partially_online(mem_ctx, ctdb, node), options.sep,
801 (node->pnn == mypnn)?'Y':'N', options.sep);
806 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
807 struct ctdb_node_map *nodemap, uint32_t mypnn,
810 struct ctdb_node_and_flags *node;
811 int num_deleted_nodes = 0;
814 for (i=0; i<nodemap->num; i++) {
815 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
821 if (num_deleted_nodes == 0) {
822 printf("Number of nodes:%d\n", nodemap->num);
824 printf("Number of nodes:%d "
825 "(including %d deleted nodes)\n",
826 nodemap->num, num_deleted_nodes);
830 for (i=0; i<nodemap->num; i++) {
831 node = &nodemap->node[i];
832 if (node->flags & NODE_FLAGS_DELETED) {
836 printf("pnn:%u %-16s %s%s\n",
838 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
839 partially_online(mem_ctx, ctdb, node) ?
841 pretty_print_flags(mem_ctx, node->flags),
842 node->pnn == mypnn ? " (THIS NODE)" : "");
846 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
847 struct ctdb_node_map *nodemap, uint32_t mypnn,
848 struct ctdb_vnn_map *vnnmap, int recmode,
853 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
855 if (vnnmap->generation == INVALID_GENERATION) {
856 printf("Generation:INVALID\n");
858 printf("Generation:%u\n", vnnmap->generation);
860 printf("Size:%d\n", vnnmap->size);
861 for (i=0; i<vnnmap->size; i++) {
862 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
865 printf("Recovery mode:%s (%d)\n",
866 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
868 printf("Recovery master:%d\n", recmaster);
871 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
872 int argc, const char **argv)
874 struct ctdb_node_map *nodemap;
875 struct ctdb_vnn_map *vnnmap;
884 nodemap = get_nodemap(ctdb, false);
885 if (nodemap == NULL) {
889 if (options.machinereadable == 1) {
890 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
894 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
895 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
900 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
901 ctdb->cmd_pnn, TIMEOUT(), &recmode);
906 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
907 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
912 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
917 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
918 int argc, const char **argv)
920 struct ctdb_uptime *uptime;
921 int ret, tmp, days, hours, minutes, seconds;
923 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
924 ctdb->cmd_pnn, TIMEOUT(), &uptime);
929 printf("Current time of node %-4u : %s",
930 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
932 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
933 seconds = tmp % 60; tmp /= 60;
934 minutes = tmp % 60; tmp /= 60;
935 hours = tmp % 24; tmp /= 24;
938 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
939 days, hours, minutes, seconds,
940 ctime(&uptime->ctdbd_start_time.tv_sec));
942 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
943 seconds = tmp % 60; tmp /= 60;
944 minutes = tmp % 60; tmp /= 60;
945 hours = tmp % 24; tmp /= 24;
948 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
949 days, hours, minutes, seconds,
950 ctime(&uptime->last_recovery_finished.tv_sec));
952 printf("Duration of last recovery/failover: %lf seconds\n",
953 timeval_delta(&uptime->last_recovery_finished,
954 &uptime->last_recovery_started));
959 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
960 int argc, const char **argv)
963 int ret, num_clients;
965 tv = timeval_current();
966 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
967 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
972 printf("response from %u time=%.6f sec (%d clients)\n",
973 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
977 const char *runstate_to_string(enum ctdb_runstate runstate);
978 enum ctdb_runstate runstate_from_string(const char *runstate_str);
980 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
981 int argc, const char **argv)
983 enum ctdb_runstate runstate;
987 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
988 ctdb->cmd_pnn, TIMEOUT(), &runstate);
994 for (i=0; i<argc; i++) {
995 enum ctdb_runstate t;
998 t = ctdb_runstate_from_string(argv[i]);
999 if (t == CTDB_RUNSTATE_UNKNOWN) {
1000 printf("Invalid run state (%s)\n", argv[i]);
1004 if (t == runstate) {
1011 printf("CTDB not in required run state (got %s)\n",
1012 ctdb_runstate_to_string(runstate));
1016 printf("%s\n", ctdb_runstate_to_string(runstate));
1020 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1021 int argc, const char **argv)
1023 struct ctdb_var_list *tun_var_list;
1032 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1033 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1036 "Failed to get list of variables from node %u\n",
1042 for (i=0; i<tun_var_list->count; i++) {
1043 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1050 printf("No such tunable %s\n", argv[0]);
1054 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1055 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1060 printf("%-26s = %u\n", argv[0], value);
1064 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1065 int argc, const char **argv)
1067 struct ctdb_var_list *tun_var_list;
1068 struct ctdb_tunable tunable;
1076 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1077 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1080 "Failed to get list of variables from node %u\n",
1086 for (i=0; i<tun_var_list->count; i++) {
1087 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1094 printf("No such tunable %s\n", argv[0]);
1098 tunable.name = argv[0];
1099 tunable.value = strtoul(argv[1], NULL, 0);
1101 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1102 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1106 "Setting obsolete tunable variable '%s'\n",
1115 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1116 int argc, const char **argv)
1118 struct ctdb_var_list *tun_var_list;
1125 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1126 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1131 for (i=0; i<tun_var_list->count; i++) {
1132 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1141 } stats_fields[] = {
1142 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1143 STATISTICS_FIELD(num_clients),
1144 STATISTICS_FIELD(frozen),
1145 STATISTICS_FIELD(recovering),
1146 STATISTICS_FIELD(num_recoveries),
1147 STATISTICS_FIELD(client_packets_sent),
1148 STATISTICS_FIELD(client_packets_recv),
1149 STATISTICS_FIELD(node_packets_sent),
1150 STATISTICS_FIELD(node_packets_recv),
1151 STATISTICS_FIELD(keepalive_packets_sent),
1152 STATISTICS_FIELD(keepalive_packets_recv),
1153 STATISTICS_FIELD(node.req_call),
1154 STATISTICS_FIELD(node.reply_call),
1155 STATISTICS_FIELD(node.req_dmaster),
1156 STATISTICS_FIELD(node.reply_dmaster),
1157 STATISTICS_FIELD(node.reply_error),
1158 STATISTICS_FIELD(node.req_message),
1159 STATISTICS_FIELD(node.req_control),
1160 STATISTICS_FIELD(node.reply_control),
1161 STATISTICS_FIELD(client.req_call),
1162 STATISTICS_FIELD(client.req_message),
1163 STATISTICS_FIELD(client.req_control),
1164 STATISTICS_FIELD(timeouts.call),
1165 STATISTICS_FIELD(timeouts.control),
1166 STATISTICS_FIELD(timeouts.traverse),
1167 STATISTICS_FIELD(locks.num_calls),
1168 STATISTICS_FIELD(locks.num_current),
1169 STATISTICS_FIELD(locks.num_pending),
1170 STATISTICS_FIELD(locks.num_failed),
1171 STATISTICS_FIELD(total_calls),
1172 STATISTICS_FIELD(pending_calls),
1173 STATISTICS_FIELD(childwrite_calls),
1174 STATISTICS_FIELD(pending_childwrite_calls),
1175 STATISTICS_FIELD(memory_used),
1176 STATISTICS_FIELD(max_hop_count),
1177 STATISTICS_FIELD(total_ro_delegations),
1178 STATISTICS_FIELD(total_ro_revokes),
1181 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1183 static void print_statistics_machine(struct ctdb_statistics *s,
1189 printf("CTDB version%s", options.sep);
1190 printf("Current time of statistics%s", options.sep);
1191 printf("Statistics collected since%s", options.sep);
1192 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1193 printf("%s%s", stats_fields[i].name, options.sep);
1195 printf("num_reclock_ctdbd_latency%s", options.sep);
1196 printf("min_reclock_ctdbd_latency%s", options.sep);
1197 printf("avg_reclock_ctdbd_latency%s", options.sep);
1198 printf("max_reclock_ctdbd_latency%s", options.sep);
1200 printf("num_reclock_recd_latency%s", options.sep);
1201 printf("min_reclock_recd_latency%s", options.sep);
1202 printf("avg_reclock_recd_latency%s", options.sep);
1203 printf("max_reclock_recd_latency%s", options.sep);
1205 printf("num_call_latency%s", options.sep);
1206 printf("min_call_latency%s", options.sep);
1207 printf("avg_call_latency%s", options.sep);
1208 printf("max_call_latency%s", options.sep);
1210 printf("num_lockwait_latency%s", options.sep);
1211 printf("min_lockwait_latency%s", options.sep);
1212 printf("avg_lockwait_latency%s", options.sep);
1213 printf("max_lockwait_latency%s", options.sep);
1215 printf("num_childwrite_latency%s", options.sep);
1216 printf("min_childwrite_latency%s", options.sep);
1217 printf("avg_childwrite_latency%s", options.sep);
1218 printf("max_childwrite_latency%s", options.sep);
1222 printf("%u%s", CTDB_PROTOCOL, options.sep);
1223 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1224 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1225 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1227 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1230 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1231 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1232 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1233 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1235 printf("%u%s", s->reclock.recd.num, options.sep);
1236 printf("%.6f%s", s->reclock.recd.min, options.sep);
1237 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1238 printf("%.6f%s", s->reclock.recd.max, options.sep);
1240 printf("%d%s", s->call_latency.num, options.sep);
1241 printf("%.6f%s", s->call_latency.min, options.sep);
1242 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1243 printf("%.6f%s", s->call_latency.max, options.sep);
1245 printf("%d%s", s->childwrite_latency.num, options.sep);
1246 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1247 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1248 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1252 static void print_statistics(struct ctdb_statistics *s)
1254 int tmp, days, hours, minutes, seconds;
1256 const char *prefix = NULL;
1259 tmp = s->statistics_current_time.tv_sec -
1260 s->statistics_start_time.tv_sec;
1261 seconds = tmp % 60; tmp /= 60;
1262 minutes = tmp % 60; tmp /= 60;
1263 hours = tmp % 24; tmp /= 24;
1266 printf("CTDB version %u\n", CTDB_PROTOCOL);
1267 printf("Current time of statistics : %s",
1268 ctime(&s->statistics_current_time.tv_sec));
1269 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1270 days, hours, minutes, seconds,
1271 ctime(&s->statistics_start_time.tv_sec));
1273 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1274 if (strchr(stats_fields[i].name, '.') != NULL) {
1275 preflen = strcspn(stats_fields[i].name, ".") + 1;
1277 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1278 prefix = stats_fields[i].name;
1279 printf(" %*.*s\n", preflen-1, preflen-1,
1280 stats_fields[i].name);
1285 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1286 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1287 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1290 printf(" hop_count_buckets:");
1291 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1292 printf(" %d", s->hop_count_bucket[i]);
1295 printf(" lock_buckets:");
1296 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1297 printf(" %d", s->locks.buckets[i]);
1300 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1301 "locks_latency MIN/AVG/MAX",
1302 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1303 s->locks.latency.max, s->locks.latency.num);
1305 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1306 "reclock_ctdbd MIN/AVG/MAX",
1307 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1308 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1310 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1311 "reclock_recd MIN/AVG/MAX",
1312 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1313 s->reclock.recd.max, s->reclock.recd.num);
1315 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1316 "call_latency MIN/AVG/MAX",
1317 s->call_latency.min, LATENCY_AVG(s->call_latency),
1318 s->call_latency.max, s->call_latency.num);
1320 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1321 "childwrite_latency MIN/AVG/MAX",
1322 s->childwrite_latency.min,
1323 LATENCY_AVG(s->childwrite_latency),
1324 s->childwrite_latency.max, s->childwrite_latency.num);
1327 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1328 int argc, const char **argv)
1330 struct ctdb_statistics *stats;
1334 usage("statistics");
1337 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1338 ctdb->cmd_pnn, TIMEOUT(), &stats);
1343 if (options.machinereadable) {
1344 print_statistics_machine(stats, true);
1346 print_statistics(stats);
1352 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1353 struct ctdb_context *ctdb,
1354 int argc, const char **argv)
1359 usage("statisticsreset");
1362 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1363 ctdb->cmd_pnn, TIMEOUT());
1371 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1372 int argc, const char **argv)
1374 struct ctdb_statistics_list *slist;
1375 int ret, count = 0, i;
1376 bool show_header = true;
1383 count = atoi(argv[0]);
1386 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1387 ctdb->cmd_pnn, TIMEOUT(), &slist);
1392 for (i=0; i<slist->num; i++) {
1393 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1396 if (options.machinereadable == 1) {
1397 print_statistics_machine(&slist->stats[i],
1399 show_header = false;
1401 print_statistics(&slist->stats[i]);
1403 if (count > 0 && i == count) {
1411 static int ctdb_public_ip_cmp(const void *a, const void *b)
1413 const struct ctdb_public_ip *ip_a = a;
1414 const struct ctdb_public_ip *ip_b = b;
1416 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1419 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1420 struct ctdb_public_ip_list *ips,
1421 struct ctdb_public_ip_info **ipinfo,
1425 char *conf, *avail, *active;
1427 if (options.machinereadable == 1) {
1428 printf("%s%s%s%s%s", options.sep,
1429 "Public IP", options.sep,
1430 "Node", options.sep);
1431 if (options.verbose == 1) {
1432 printf("%s%s%s%s%s%s\n",
1433 "ActiveInterfaces", options.sep,
1434 "AvailableInterfaces", options.sep,
1435 "ConfiguredInterfaces", options.sep);
1441 printf("Public IPs on ALL nodes\n");
1443 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1447 for (i = 0; i < ips->num; i++) {
1449 if (options.machinereadable == 1) {
1450 printf("%s%s%s%d%s", options.sep,
1451 ctdb_sock_addr_to_string(
1452 mem_ctx, &ips->ip[i].addr, false),
1454 (int)ips->ip[i].pnn, options.sep);
1456 printf("%s", ctdb_sock_addr_to_string(
1457 mem_ctx, &ips->ip[i].addr, false));
1460 if (options.verbose == 0) {
1461 if (options.machinereadable == 1) {
1464 printf(" %d\n", (int)ips->ip[i].pnn);
1473 if (ipinfo[i] == NULL) {
1477 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1478 struct ctdb_iface *iface;
1480 iface = &ipinfo[i]->ifaces->iface[j];
1482 conf = talloc_strdup(mem_ctx, iface->name);
1484 conf = talloc_asprintf_append(
1485 conf, ",%s", iface->name);
1488 if (ipinfo[i]->active_idx == j) {
1489 active = iface->name;
1492 if (iface->link_state == 0) {
1496 if (avail == NULL) {
1497 avail = talloc_strdup(mem_ctx, iface->name);
1499 avail = talloc_asprintf_append(
1500 avail, ",%s", iface->name);
1506 if (options.machinereadable == 1) {
1507 printf("%s%s%s%s%s%s\n",
1508 active ? active : "", options.sep,
1509 avail ? avail : "", options.sep,
1510 conf ? conf : "", options.sep);
1512 printf(" node[%d] active[%s] available[%s]"
1513 " configured[%s]\n",
1514 (int)ips->ip[i].pnn, active ? active : "",
1515 avail ? avail : "", conf ? conf : "");
1520 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1521 size_t datalen, void *private_data)
1523 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1524 private_data, struct ctdb_public_ip_list);
1525 struct ctdb_public_ip *ip;
1527 ip = (struct ctdb_public_ip *)databuf;
1528 ips->ip[ips->num] = *ip;
1534 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1535 struct ctdb_public_ip_list **out)
1537 struct ctdb_node_map *nodemap;
1538 struct ctdb_public_ip_list *ips;
1539 struct db_hash_context *ipdb;
1541 int ret, count, i, j;
1543 nodemap = get_nodemap(ctdb, false);
1544 if (nodemap == NULL) {
1548 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1553 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1559 for (i=0; i<count; i++) {
1560 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1561 pnn_list[i], TIMEOUT(),
1567 for (j=0; j<ips->num; j++) {
1568 struct ctdb_public_ip ip;
1570 ip.pnn = ips->ip[j].pnn;
1571 ip.addr = ips->ip[j].addr;
1573 if (pnn_list[i] == ip.pnn) {
1574 /* Node claims IP is hosted on it, so
1575 * save that information
1577 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1579 (uint8_t *)&ip, sizeof(ip));
1584 /* Node thinks IP is hosted elsewhere,
1585 * so overwrite with CTDB_UNKNOWN_PNN
1586 * if there's no existing entry
1588 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1590 if (ret == ENOENT) {
1591 ip.pnn = CTDB_UNKNOWN_PNN;
1592 ret = db_hash_add(ipdb,
1593 (uint8_t *)&ip.addr,
1607 talloc_free(pnn_list);
1609 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1614 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1619 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1620 if (ips->ip == NULL) {
1624 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1629 if (count != ips->num) {
1643 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1644 int argc, const char **argv)
1646 struct ctdb_public_ip_list *ips;
1647 struct ctdb_public_ip_info **ipinfo;
1649 bool do_all = false;
1656 if (strcmp(argv[0], "all") == 0) {
1664 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1666 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1667 ctdb->cmd_pnn, TIMEOUT(),
1674 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1675 ctdb_public_ip_cmp);
1677 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1678 if (ipinfo == NULL) {
1682 for (i=0; i<ips->num; i++) {
1685 pnn = ips->ip[i].pnn;
1687 pnn = ctdb->cmd_pnn;
1689 if (pnn == CTDB_UNKNOWN_PNN) {
1693 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1695 TIMEOUT(), &ips->ip[i].addr,
1702 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1706 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1707 int argc, const char **argv)
1709 struct ctdb_public_ip_info *ipinfo;
1710 ctdb_sock_addr addr;
1717 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1718 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1722 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1723 ctdb->cmd_pnn, TIMEOUT(), &addr,
1727 printf("Node %u does not know about IP %s\n",
1728 ctdb->cmd_pnn, argv[0]);
1733 printf("Public IP[%s] info on node %u\n",
1734 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1737 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1738 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1739 ipinfo->ip.pnn, ipinfo->ifaces->num);
1741 for (i=0; i<ipinfo->ifaces->num; i++) {
1742 struct ctdb_iface *iface;
1744 iface = &ipinfo->ifaces->iface[i];
1745 iface->name[CTDB_IFACE_SIZE] = '\0';
1746 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1748 iface->link_state == 0 ? "down" : "up",
1750 (i == ipinfo->active_idx) ? " (active)" : "");
1756 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1757 int argc, const char **argv)
1759 struct ctdb_iface_list *ifaces;
1766 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1767 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1772 if (ifaces->num == 0) {
1773 printf("No interfaces configured on node %u\n",
1778 if (options.machinereadable) {
1779 printf("%s%s%s%s%s%s%s\n", options.sep,
1780 "Name", options.sep,
1781 "LinkStatus", options.sep,
1782 "References", options.sep);
1784 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1787 for (i=0; i<ifaces->num; i++) {
1788 if (options.machinereadable) {
1789 printf("%s%s%s%u%s%u%s\n", options.sep,
1790 ifaces->iface[i].name, options.sep,
1791 ifaces->iface[i].link_state, options.sep,
1792 ifaces->iface[i].references, options.sep);
1794 printf("name:%s link:%s references:%u\n",
1795 ifaces->iface[i].name,
1796 ifaces->iface[i].link_state ? "up" : "down",
1797 ifaces->iface[i].references);
1804 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1805 int argc, const char **argv)
1807 struct ctdb_iface_list *ifaces;
1808 struct ctdb_iface *iface;
1812 usage("setifacelink");
1815 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1816 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1820 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1821 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1824 "Failed to get interface information from node %u\n",
1830 for (i=0; i<ifaces->num; i++) {
1831 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1832 iface = &ifaces->iface[i];
1837 if (iface == NULL) {
1838 printf("Interface %s not configured on node %u\n",
1839 argv[0], ctdb->cmd_pnn);
1843 if (strcmp(argv[1], "up") == 0) {
1844 iface->link_state = 1;
1845 } else if (strcmp(argv[1], "down") == 0) {
1846 iface->link_state = 0;
1848 usage("setifacelink");
1852 iface->references = 0;
1854 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1855 ctdb->cmd_pnn, TIMEOUT(), iface);
1863 static int control_process_exists(TALLOC_CTX *mem_ctx,
1864 struct ctdb_context *ctdb,
1865 int argc, const char **argv)
1871 if (argc != 1 && argc != 2) {
1872 usage("process-exists");
1875 pid = atoi(argv[0]);
1877 srvid = strtoull(argv[1], NULL, 0);
1881 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1882 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1884 struct ctdb_pid_srvid pid_srvid;
1886 pid_srvid.pid = pid;
1887 pid_srvid.srvid = srvid;
1889 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
1890 ctdb->client, ctdb->cmd_pnn,
1891 TIMEOUT(), &pid_srvid,
1900 printf("PID %d %s\n", pid,
1901 (status == 0 ? "exists" : "does not exist"));
1903 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
1904 (status == 0 ? "exists" : "does not exist"));
1909 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1910 int argc, const char **argv)
1912 struct ctdb_dbid_map *dbmap;
1919 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1920 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1925 if (options.machinereadable == 1) {
1926 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1929 "Name", options.sep,
1930 "Path", options.sep,
1931 "Persistent", options.sep,
1932 "Sticky", options.sep,
1933 "Unhealthy", options.sep,
1934 "Readonly", options.sep,
1935 "Replicated", options.sep);
1937 printf("Number of databases:%d\n", dbmap->num);
1940 for (i=0; i<dbmap->num; i++) {
1950 db_id = dbmap->dbs[i].db_id;
1952 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1953 ctdb->cmd_pnn, TIMEOUT(), db_id,
1959 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1960 ctdb->cmd_pnn, TIMEOUT(), db_id,
1966 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1967 ctdb->cmd_pnn, TIMEOUT(), db_id,
1973 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1974 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1975 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1976 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
1978 if (options.machinereadable == 1) {
1979 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1984 !! (persistent), options.sep,
1985 !! (sticky), options.sep,
1986 !! (health), options.sep,
1987 !! (readonly), options.sep,
1988 !! (replicated), options.sep);
1990 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1992 persistent ? " PERSISTENT" : "",
1993 sticky ? " STICKY" : "",
1994 readonly ? " READONLY" : "",
1995 replicated ? " REPLICATED" : "",
1996 health ? " UNHEALTHY" : "");
1999 talloc_free(discard_const(name));
2000 talloc_free(discard_const(path));
2001 talloc_free(discard_const(health));
2007 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2008 int argc, const char **argv)
2011 const char *db_name, *db_path, *db_health;
2016 usage("getdbstatus");
2019 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2023 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2024 ctdb->cmd_pnn, TIMEOUT(), db_id,
2030 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2031 ctdb->cmd_pnn, TIMEOUT(), db_id,
2037 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2038 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2039 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2040 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2041 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2042 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2043 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2047 struct dump_record_state {
2051 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2053 static void dump_tdb_data(const char *name, TDB_DATA val)
2057 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2058 for (i=0; i<val.dsize; i++) {
2059 if (ISASCII(val.dptr[i])) {
2060 fprintf(stdout, "%c", val.dptr[i]);
2062 fprintf(stdout, "\\%02X", val.dptr[i]);
2065 fprintf(stdout, "\"\n");
2068 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2070 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2071 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2072 fprintf(stdout, "flags: 0x%08x", header->flags);
2073 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2074 fprintf(stdout, " MIGRATED_WITH_DATA");
2076 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2077 fprintf(stdout, " VACUUM_MIGRATED");
2079 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2080 fprintf(stdout, " AUTOMATIC");
2082 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2083 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2085 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2086 fprintf(stdout, " RO_HAVE_READONLY");
2088 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2089 fprintf(stdout, " RO_REVOKING_READONLY");
2091 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2092 fprintf(stdout, " RO_REVOKE_COMPLETE");
2094 fprintf(stdout, "\n");
2098 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2099 TDB_DATA key, TDB_DATA data, void *private_data)
2101 struct dump_record_state *state =
2102 (struct dump_record_state *)private_data;
2106 dump_tdb_data("key", key);
2107 dump_ltdb_header(header);
2108 dump_tdb_data("data", data);
2109 fprintf(stdout, "\n");
2114 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2115 int argc, const char **argv)
2117 struct ctdb_db_context *db;
2118 const char *db_name;
2121 struct dump_record_state state;
2128 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2132 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2135 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2141 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2142 ctdb->cmd_pnn, TIMEOUT(),
2143 dump_record, &state);
2145 printf("Dumped %u records\n", state.count);
2150 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2151 int argc, const char **argv)
2153 struct ctdb_db_context *db;
2154 const char *db_name;
2157 struct dump_record_state state;
2164 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2168 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2171 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2176 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2178 printf("Dumped %u record(s)\n", state.count);
2183 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2184 struct ctdb_context *ctdb,
2185 int argc, const char **argv)
2191 usage("getcapabilities");
2194 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2195 ctdb->cmd_pnn, TIMEOUT(), &caps);
2200 if (options.machinereadable == 1) {
2201 printf("%s%s%s%s%s\n",
2203 "RECMASTER", options.sep,
2204 "LMASTER", options.sep);
2205 printf("%s%d%s%d%s\n", options.sep,
2206 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2207 !! (caps & CTDB_CAP_LMASTER), options.sep);
2209 printf("RECMASTER: %s\n",
2210 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2211 printf("LMASTER: %s\n",
2212 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2218 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2219 int argc, const char **argv)
2221 printf("%u\n", ctdb_client_pnn(ctdb->client));
2225 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2226 int argc, const char **argv)
2228 char *t, *lvs_helper = NULL;
2234 t = getenv("CTDB_LVS_HELPER");
2236 lvs_helper = talloc_strdup(mem_ctx, t);
2238 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2239 CTDB_HELPER_BINDIR);
2242 if (lvs_helper == NULL) {
2243 fprintf(stderr, "Unable to set LVS helper\n");
2247 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2250 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2251 int argc, const char **argv)
2261 found = debug_level_parse(argv[0], &log_level);
2264 "Invalid debug level '%s'. Valid levels are:\n",
2266 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2270 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2271 ctdb->cmd_pnn, TIMEOUT(), log_level);
2279 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2280 int argc, const char **argv)
2283 const char *log_str;
2290 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2291 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2296 log_str = debug_level_to_string(loglevel);
2297 printf("%s\n", log_str);
2302 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2303 int argc, const char **argv)
2305 const char *db_name;
2306 uint8_t db_flags = 0;
2309 if (argc < 1 || argc > 2) {
2315 if (strcmp(argv[1], "persistent") == 0) {
2316 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2317 } else if (strcmp(argv[1], "readonly") == 0) {
2318 db_flags = CTDB_DB_FLAGS_READONLY;
2319 } else if (strcmp(argv[1], "sticky") == 0) {
2320 db_flags = CTDB_DB_FLAGS_STICKY;
2321 } else if (strcmp(argv[1], "replicated") == 0) {
2322 db_flags = CTDB_DB_FLAGS_REPLICATED;
2328 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2337 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2338 int argc, const char **argv)
2340 const char *db_name;
2343 struct ctdb_node_map *nodemap;
2351 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2352 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2357 if (recmode == CTDB_RECOVERY_ACTIVE) {
2358 fprintf(stderr, "Database cannot be detached"
2359 " when recovery is active\n");
2363 nodemap = get_nodemap(ctdb, false);
2364 if (nodemap == NULL) {
2368 for (i=0; i<nodemap->num; i++) {
2371 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2374 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2377 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2378 fprintf(stderr, "Database cannot be detached on"
2379 " inactive (stopped or banned) node %u\n",
2380 nodemap->node[i].pnn);
2384 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2385 nodemap->node[i].pnn, TIMEOUT(),
2386 "AllowClientDBAttach", &value);
2389 "Unable to get tunable AllowClientDBAttach"
2390 " from node %u\n", nodemap->node[i].pnn);
2396 "Database access is still active on node %u."
2397 " Set AllowclientDBAttach=0 on all nodes.\n",
2398 nodemap->node[i].pnn);
2404 for (i=0; i<argc; i++) {
2405 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2411 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2413 "Only volatile databases can be detached\n");
2417 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2419 fprintf(stderr, "Database %s detach failed\n", db_name);
2427 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2428 int argc, const char **argv)
2430 const char *mem_str;
2434 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2435 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2440 n = write(1, mem_str, strlen(mem_str)+1);
2441 if (n < 0 || n != strlen(mem_str)+1) {
2442 fprintf(stderr, "Failed to write talloc summary\n");
2449 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2451 bool *done = (bool *)private_data;
2454 n = write(1, data.dptr, data.dsize);
2455 if (n < 0 || n != data.dsize) {
2456 fprintf(stderr, "Failed to write talloc summary\n");
2462 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2463 int argc, const char **argv)
2465 struct ctdb_srvid_message msg = { 0 };
2469 msg.pnn = ctdb->pnn;
2470 msg.srvid = next_srvid(ctdb);
2472 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2473 msg.srvid, dump_memory, &done);
2478 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2479 ctdb->cmd_pnn, &msg);
2484 ctdb_client_wait(ctdb->ev, &done);
2488 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2489 int argc, const char **argv)
2494 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2495 ctdb->cmd_pnn, TIMEOUT(), &pid);
2500 printf("%u\n", pid);
2504 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2505 const char *desc, uint32_t flag, bool set_flag)
2507 struct ctdb_node_map *nodemap;
2510 nodemap = get_nodemap(ctdb, false);
2511 if (nodemap == NULL) {
2515 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2516 if (set_flag == flag_is_set) {
2518 fprintf(stderr, "Node %u is already %s\n",
2519 ctdb->cmd_pnn, desc);
2521 fprintf(stderr, "Node %u is not %s\n",
2522 ctdb->cmd_pnn, desc);
2530 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2531 uint32_t flag, bool set_flag)
2533 struct ctdb_node_map *nodemap;
2537 nodemap = get_nodemap(ctdb, true);
2538 if (nodemap == NULL) {
2540 "Failed to get nodemap, trying again\n");
2545 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2546 if (flag_is_set == set_flag) {
2554 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2555 struct ctdb_client_context *client,
2556 uint32_t destnode, struct timeval timeout,
2557 uint32_t set, uint32_t clear)
2559 struct ctdb_node_map *nodemap;
2560 struct ctdb_node_flag_change flag_change;
2561 struct ctdb_req_control request;
2565 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2566 tevent_timeval_zero(), &nodemap);
2571 flag_change.pnn = destnode;
2572 flag_change.old_flags = nodemap->node[destnode].flags;
2573 flag_change.new_flags = flag_change.old_flags | set;
2574 flag_change.new_flags &= ~clear;
2576 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2581 ctdb_req_control_modify_flags(&request, &flag_change);
2582 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2583 tevent_timeval_zero(), &request,
2588 struct ipreallocate_state {
2593 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2596 struct ipreallocate_state *state =
2597 (struct ipreallocate_state *)private_data;
2599 if (data.dsize != sizeof(int)) {
2604 state->status = *(int *)data.dptr;
2608 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2610 struct ctdb_srvid_message msg = { 0 };
2611 struct ipreallocate_state state;
2614 msg.pnn = ctdb->pnn;
2615 msg.srvid = next_srvid(ctdb);
2618 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2620 ipreallocate_handler, &state);
2626 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2628 CTDB_BROADCAST_CONNECTED,
2634 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2640 if (state.status >= 0) {
2649 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2654 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2655 int argc, const char **argv)
2663 ret = check_flags(mem_ctx, ctdb, "disabled",
2664 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2669 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2670 ctdb->cmd_pnn, TIMEOUT(),
2671 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2674 "Failed to set DISABLED flag on node %u\n",
2679 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2680 return ipreallocate(mem_ctx, ctdb);
2683 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2684 int argc, const char **argv)
2692 ret = check_flags(mem_ctx, ctdb, "disabled",
2693 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2698 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2699 ctdb->cmd_pnn, TIMEOUT(),
2700 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2702 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2707 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2708 return ipreallocate(mem_ctx, ctdb);
2711 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2712 int argc, const char **argv)
2720 ret = check_flags(mem_ctx, ctdb, "stopped",
2721 NODE_FLAGS_STOPPED, true);
2726 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2727 ctdb->cmd_pnn, TIMEOUT());
2729 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2733 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2734 return ipreallocate(mem_ctx, ctdb);
2737 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2738 int argc, const char **argv)
2746 ret = check_flags(mem_ctx, ctdb, "stopped",
2747 NODE_FLAGS_STOPPED, false);
2752 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2753 ctdb->cmd_pnn, TIMEOUT());
2755 fprintf(stderr, "Failed to continue stopped node %u\n",
2760 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2761 return ipreallocate(mem_ctx, ctdb);
2764 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2765 int argc, const char **argv)
2767 struct ctdb_ban_state ban_state;
2774 ret = check_flags(mem_ctx, ctdb, "banned",
2775 NODE_FLAGS_BANNED, true);
2780 ban_state.pnn = ctdb->cmd_pnn;
2781 ban_state.time = strtoul(argv[0], NULL, 0);
2783 if (ban_state.time == 0) {
2784 fprintf(stderr, "Ban time cannot be zero\n");
2788 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2789 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2791 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2795 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2796 return ipreallocate(mem_ctx, ctdb);
2800 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2801 int argc, const char **argv)
2803 struct ctdb_ban_state ban_state;
2810 ret = check_flags(mem_ctx, ctdb, "banned",
2811 NODE_FLAGS_BANNED, false);
2816 ban_state.pnn = ctdb->cmd_pnn;
2819 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2820 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2822 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2826 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2827 return ipreallocate(mem_ctx, ctdb);
2831 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2832 int argc, const char **argv)
2840 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2841 ctdb->cmd_pnn, TIMEOUT());
2843 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2850 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2851 uint32_t *generation)
2855 struct ctdb_vnn_map *vnnmap;
2859 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2860 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2862 fprintf(stderr, "Failed to find recovery master\n");
2866 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2867 recmaster, TIMEOUT(), &recmode);
2869 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2874 if (recmode == CTDB_RECOVERY_ACTIVE) {
2879 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2880 recmaster, TIMEOUT(), &vnnmap);
2882 fprintf(stderr, "Failed to get generation from node %u\n",
2887 if (vnnmap->generation == INVALID_GENERATION) {
2888 talloc_free(vnnmap);
2893 *generation = vnnmap->generation;
2894 talloc_free(vnnmap);
2899 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2900 int argc, const char **argv)
2902 uint32_t generation, next_generation;
2909 ret = get_generation(mem_ctx, ctdb, &generation);
2914 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2915 ctdb->cmd_pnn, TIMEOUT(),
2916 CTDB_RECOVERY_ACTIVE);
2918 fprintf(stderr, "Failed to set recovery mode active\n");
2923 ret = get_generation(mem_ctx, ctdb, &next_generation);
2926 "Failed to confirm end of recovery\n");
2930 if (next_generation != generation) {
2940 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2941 int argc, const char **argv)
2944 usage("ipreallocate");
2947 return ipreallocate(mem_ctx, ctdb);
2950 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2951 struct ctdb_context *ctdb,
2952 int argc, const char **argv)
2958 usage("isnotrecmaster");
2961 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2962 ctdb->pnn, TIMEOUT(), &recmaster);
2964 fprintf(stderr, "Failed to get recmaster\n");
2968 if (recmaster != ctdb->pnn) {
2969 printf("this node is not the recmaster\n");
2973 printf("this node is the recmaster\n");
2977 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2978 int argc, const char **argv)
2980 struct ctdb_addr_info addr_info;
2987 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
2988 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
2991 addr_info.iface = argv[1];
2993 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
2994 ctdb->cmd_pnn, TIMEOUT(),
2997 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3005 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3006 int argc, const char **argv)
3008 ctdb_sock_addr src, dst;
3011 if (argc != 0 && argc != 2) {
3016 struct ctdb_connection *clist;
3020 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3026 for (i=0; i<count; i++) {
3027 ret = ctdb_sys_send_tcp(&clist[i].src,
3037 if (num_failed > 0) {
3038 fprintf(stderr, "Failed to send %d tickles\n",
3047 if (! parse_ip_port(argv[0], &src)) {
3048 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3052 if (! parse_ip_port(argv[1], &dst)) {
3053 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3057 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3059 fprintf(stderr, "Failed to send tickle ack\n");
3066 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3067 int argc, const char **argv)
3069 ctdb_sock_addr addr;
3070 struct ctdb_tickle_list *tickles;
3074 if (argc < 1 || argc > 2) {
3075 usage("gettickles");
3079 port = strtoul(argv[1], NULL, 10);
3082 if (! parse_ip(argv[0], NULL, port, &addr)) {
3083 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3087 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3088 ctdb->cmd_pnn, TIMEOUT(), &addr,
3091 fprintf(stderr, "Failed to get list of connections\n");
3095 if (options.machinereadable) {
3096 printf("%s%s%s%s%s%s%s%s%s\n",
3098 "Source IP", options.sep,
3099 "Port", options.sep,
3100 "Destiation IP", options.sep,
3101 "Port", options.sep);
3102 for (i=0; i<tickles->num; i++) {
3103 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3104 ctdb_sock_addr_to_string(
3105 mem_ctx, &tickles->conn[i].src, false),
3107 ntohs(tickles->conn[i].src.ip.sin_port),
3109 ctdb_sock_addr_to_string(
3110 mem_ctx, &tickles->conn[i].dst, false),
3112 ntohs(tickles->conn[i].dst.ip.sin_port),
3116 printf("Connections for IP: %s\n",
3117 ctdb_sock_addr_to_string(mem_ctx,
3118 &tickles->addr, false));
3119 printf("Num connections: %u\n", tickles->num);
3120 for (i=0; i<tickles->num; i++) {
3121 printf("SRC: %s DST: %s\n",
3122 ctdb_sock_addr_to_string(
3123 mem_ctx, &tickles->conn[i].src, true),
3124 ctdb_sock_addr_to_string(
3125 mem_ctx, &tickles->conn[i].dst, true));
3129 talloc_free(tickles);
3133 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3134 struct ctdb_connection *conn);
3136 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3138 struct process_clist_state {
3139 struct ctdb_connection *clist;
3141 int num_failed, num_total;
3142 clist_reply_func reply_func;
3145 static void process_clist_done(struct tevent_req *subreq);
3147 static struct tevent_req *process_clist_send(
3148 TALLOC_CTX *mem_ctx,
3149 struct ctdb_context *ctdb,
3150 struct ctdb_connection *clist,
3152 clist_request_func request_func,
3153 clist_reply_func reply_func)
3155 struct tevent_req *req, *subreq;
3156 struct process_clist_state *state;
3157 struct ctdb_req_control request;
3160 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3165 state->clist = clist;
3166 state->count = count;
3167 state->reply_func = reply_func;
3169 for (i=0; i<count; i++) {
3170 request_func(&request, &clist[i]);
3171 subreq = ctdb_client_control_send(state, ctdb->ev,
3172 ctdb->client, ctdb->cmd_pnn,
3173 TIMEOUT(), &request);
3174 if (tevent_req_nomem(subreq, req)) {
3175 return tevent_req_post(req, ctdb->ev);
3177 tevent_req_set_callback(subreq, process_clist_done, req);
3183 static void process_clist_done(struct tevent_req *subreq)
3185 struct tevent_req *req = tevent_req_callback_data(
3186 subreq, struct tevent_req);
3187 struct process_clist_state *state = tevent_req_data(
3188 req, struct process_clist_state);
3189 struct ctdb_reply_control *reply;
3193 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3194 TALLOC_FREE(subreq);
3196 state->num_failed += 1;
3200 ret = state->reply_func(reply);
3202 state->num_failed += 1;
3207 state->num_total += 1;
3208 if (state->num_total == state->count) {
3209 tevent_req_done(req);
3213 static int process_clist_recv(struct tevent_req *req)
3215 struct process_clist_state *state = tevent_req_data(
3216 req, struct process_clist_state);
3218 return state->num_failed;
3221 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3222 int argc, const char **argv)
3224 struct ctdb_connection conn;
3227 if (argc != 0 && argc != 2) {
3232 struct ctdb_connection *clist;
3233 struct tevent_req *req;
3236 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3244 req = process_clist_send(mem_ctx, ctdb, clist, count,
3245 ctdb_req_control_tcp_add_delayed_update,
3246 ctdb_reply_control_tcp_add_delayed_update);
3252 tevent_req_poll(req, ctdb->ev);
3255 ret = process_clist_recv(req);
3257 fprintf(stderr, "Failed to add %d tickles\n", ret);
3264 if (! parse_ip_port(argv[0], &conn.src)) {
3265 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3268 if (! parse_ip_port(argv[1], &conn.dst)) {
3269 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3273 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3274 ctdb->client, ctdb->cmd_pnn,
3277 fprintf(stderr, "Failed to register connection\n");
3284 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3285 int argc, const char **argv)
3287 struct ctdb_connection conn;
3290 if (argc != 0 && argc != 2) {
3295 struct ctdb_connection *clist;
3296 struct tevent_req *req;
3299 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3307 req = process_clist_send(mem_ctx, ctdb, clist, count,
3308 ctdb_req_control_tcp_remove,
3309 ctdb_reply_control_tcp_remove);
3315 tevent_req_poll(req, ctdb->ev);
3318 ret = process_clist_recv(req);
3320 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3327 if (! parse_ip_port(argv[0], &conn.src)) {
3328 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3331 if (! parse_ip_port(argv[1], &conn.dst)) {
3332 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3336 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3337 ctdb->cmd_pnn, TIMEOUT(), &conn);
3339 fprintf(stderr, "Failed to unregister connection\n");
3346 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3347 int argc, const char **argv)
3349 struct ctdb_node_map *nodemap;
3356 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3357 if (nodemap == NULL) {
3361 for (i=0; i<nodemap->num; i++) {
3362 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3366 if (options.machinereadable) {
3367 printf("%s%u%s%s%s\n", options.sep,
3368 nodemap->node[i].pnn, options.sep,
3369 ctdb_sock_addr_to_string(
3370 mem_ctx, &nodemap->node[i].addr, false),
3374 ctdb_sock_addr_to_string(
3375 mem_ctx, &nodemap->node[i].addr, false));
3382 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3383 struct ctdb_node_map *nodemap2)
3387 if (nodemap1->num != nodemap2->num) {
3391 for (i=0; i<nodemap1->num; i++) {
3392 struct ctdb_node_and_flags *n1, *n2;
3394 n1 = &nodemap1->node[i];
3395 n2 = &nodemap2->node[i];
3397 if ((n1->pnn != n2->pnn) ||
3398 (n1->flags != n2->flags) ||
3399 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3407 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3408 struct ctdb_node_map *nm,
3409 struct ctdb_node_map *fnm,
3413 bool check_failed = false;
3417 for (i=0; i<nm->num; i++) {
3418 if (i >= fnm->num) {
3420 "Node %u (%s) missing from nodes file\n",
3422 ctdb_sock_addr_to_string(
3423 mem_ctx, &nm->node[i].addr, false));
3424 check_failed = true;
3427 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3428 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3429 /* Node remains deleted */
3433 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3434 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3435 /* Node not newly nor previously deleted */
3436 if (! ctdb_same_ip(&nm->node[i].addr,
3437 &fnm->node[i].addr)) {
3439 "Node %u has changed IP address"
3440 " (was %s, now %s)\n",
3442 ctdb_sock_addr_to_string(
3444 &nm->node[i].addr, false),
3445 ctdb_sock_addr_to_string(
3447 &fnm->node[i].addr, false));
3448 check_failed = true;
3450 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3452 "WARNING: Node %u is disconnected."
3453 " You MUST fix this node manually!\n",
3460 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3461 /* Node is being deleted */
3462 printf("Node %u is DELETED\n", nm->node[i].pnn);
3464 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3466 "ERROR: Node %u is still connected\n",
3468 check_failed = true;
3473 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3474 /* Node was previously deleted */
3475 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3482 "ERROR: Nodes will not be reloaded due to previous error\n");
3486 /* Leftover nodes in file are NEW */
3487 for (; i < fnm->num; i++) {
3488 printf("Node %u is NEW\n", fnm->node[i].pnn);
3495 struct disable_recoveries_state {
3503 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3506 struct disable_recoveries_state *state =
3507 (struct disable_recoveries_state *)private_data;
3510 if (data.dsize != sizeof(int)) {
3515 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3516 ret = *(int *)data.dptr;
3518 state->status = ret;
3522 for (i=0; i<state->node_count; i++) {
3523 if (state->pnn_list[i] == ret) {
3524 state->reply[i] = true;
3530 for (i=0; i<state->node_count; i++) {
3531 if (! state->reply[i]) {
3532 state->done = false;
3538 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3539 uint32_t timeout, uint32_t *pnn_list, int count)
3541 struct ctdb_disable_message disable = { 0 };
3542 struct disable_recoveries_state state;
3545 disable.pnn = ctdb->pnn;
3546 disable.srvid = next_srvid(ctdb);
3547 disable.timeout = timeout;
3549 state.pnn_list = pnn_list;
3550 state.node_count = count;
3553 state.reply = talloc_zero_array(mem_ctx, bool, count);
3554 if (state.reply == NULL) {
3558 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3560 disable_recoveries_handler,
3566 for (i=0; i<count; i++) {
3567 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3576 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3578 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3580 ret = (state.status >= 0 ? 0 : 1);
3584 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3585 disable.srvid, &state);
3589 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3590 int argc, const char **argv)
3592 struct ctdb_node_map *nodemap = NULL;
3593 struct ctdb_node_map *file_nodemap;
3594 struct ctdb_node_map *remote_nodemap;
3595 struct ctdb_req_control request;
3596 struct ctdb_reply_control **reply;
3602 nodemap = get_nodemap(ctdb, false);
3603 if (nodemap == NULL) {
3607 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3608 if (file_nodemap == NULL) {
3612 for (i=0; i<nodemap->num; i++) {
3613 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3617 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3618 nodemap->node[i].pnn, TIMEOUT(),
3622 "ERROR: Failed to get nodes file from node %u\n",
3623 nodemap->node[i].pnn);
3627 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3629 "ERROR: Nodes file on node %u differs"
3630 " from current node (%u)\n",
3631 nodemap->node[i].pnn, ctdb->pnn);
3636 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3642 fprintf(stderr, "No change in nodes file,"
3643 " skipping unnecessary reload\n");
3647 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3648 mem_ctx, &pnn_list);
3650 fprintf(stderr, "Memory allocation error\n");
3654 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3657 fprintf(stderr, "Failed to disable recoveries\n");
3661 ctdb_req_control_reload_nodes_file(&request);
3662 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3663 pnn_list, count, TIMEOUT(),
3664 &request, NULL, &reply);
3666 bool failed = false;
3668 for (i=0; i<count; i++) {
3669 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3672 "Node %u failed to reload nodes\n",
3679 "You MUST fix failed nodes manually!\n");
3683 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3685 fprintf(stderr, "Failed to enable recoveries\n");
3692 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3693 ctdb_sock_addr *addr, uint32_t pnn)
3695 struct ctdb_public_ip_list *pubip_list;
3696 struct ctdb_public_ip pubip;
3697 struct ctdb_node_map *nodemap;
3698 struct ctdb_req_control request;
3702 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3703 CTDB_BROADCAST_CONNECTED,
3704 2*options.timelimit);
3706 fprintf(stderr, "Failed to disable IP check\n");
3710 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3711 pnn, TIMEOUT(), false, &pubip_list);
3713 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3718 for (i=0; i<pubip_list->num; i++) {
3719 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3724 if (i == pubip_list->num) {
3725 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3726 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3730 nodemap = get_nodemap(ctdb, false);
3731 if (nodemap == NULL) {
3735 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3737 fprintf(stderr, "Memory allocation error\n");
3743 ctdb_req_control_release_ip(&request, &pubip);
3745 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3746 pnn_list, count, TIMEOUT(),
3747 &request, NULL, NULL);
3749 fprintf(stderr, "Failed to release IP on nodes\n");
3753 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3754 pnn, TIMEOUT(), &pubip);
3756 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3763 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3764 int argc, const char **argv)
3766 ctdb_sock_addr addr;
3768 int ret, retries = 0;
3774 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3775 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3779 pnn = strtoul(argv[1], NULL, 10);
3780 if (pnn == CTDB_UNKNOWN_PNN) {
3781 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3785 while (retries < 5) {
3786 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3796 fprintf(stderr, "Failed to move IP %s to node %u\n",
3804 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3809 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3810 CTDB_BROADCAST_CONNECTED, pnn);
3813 "Failed to ask recovery master to distribute IPs\n");
3820 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3821 int argc, const char **argv)
3823 ctdb_sock_addr addr;
3824 struct ctdb_public_ip_list *pubip_list;
3825 struct ctdb_addr_info addr_info;
3827 int ret, i, retries = 0;
3833 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3834 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3838 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3839 ctdb->cmd_pnn, TIMEOUT(),
3840 false, &pubip_list);
3842 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3847 for (i=0; i<pubip_list->num; i++) {
3848 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3849 fprintf(stderr, "Node already knows about IP %s\n",
3850 ctdb_sock_addr_to_string(mem_ctx,
3856 addr_info.addr = addr;
3857 addr_info.mask = mask;
3858 addr_info.iface = argv[1];
3860 while (retries < 5) {
3861 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3862 ctdb->cmd_pnn, TIMEOUT(),
3873 fprintf(stderr, "Failed to add public IP to node %u."
3874 " Giving up\n", ctdb->cmd_pnn);
3878 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3886 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3887 int argc, const char **argv)
3889 ctdb_sock_addr addr;
3890 struct ctdb_public_ip_list *pubip_list;
3891 struct ctdb_addr_info addr_info;
3898 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3899 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3903 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3904 ctdb->cmd_pnn, TIMEOUT(),
3905 false, &pubip_list);
3907 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3912 for (i=0; i<pubip_list->num; i++) {
3913 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3918 if (i == pubip_list->num) {
3919 fprintf(stderr, "Node does not know about IP address %s\n",
3920 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
3924 addr_info.addr = addr;
3926 addr_info.iface = NULL;
3928 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3929 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3931 fprintf(stderr, "Failed to delete public IP from node %u\n",
3939 #define DB_VERSION 3
3940 #define MAX_DB_NAME 64
3941 #define MAX_REC_BUFFER_SIZE (100*1000)
3944 unsigned long version;
3946 unsigned long flags;
3949 char name[MAX_DB_NAME];
3952 struct backup_state {
3953 TALLOC_CTX *mem_ctx;
3954 struct ctdb_rec_buffer *recbuf;
3957 unsigned int nbuf, nrec;
3960 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
3961 TDB_DATA key, TDB_DATA data, void *private_data)
3963 struct backup_state *state = (struct backup_state *)private_data;
3967 if (state->recbuf == NULL) {
3968 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
3970 if (state->recbuf == NULL) {
3975 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
3981 len = ctdb_rec_buffer_len(state->recbuf);
3982 if (len < MAX_REC_BUFFER_SIZE) {
3986 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
3988 fprintf(stderr, "Failed to write records to backup file\n");
3993 state->nrec += state->recbuf->count;
3994 TALLOC_FREE(state->recbuf);
3999 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4000 int argc, const char **argv)
4002 const char *db_name;
4003 struct ctdb_db_context *db;
4006 struct backup_state state;
4007 struct db_header db_hdr;
4014 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4018 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4021 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4025 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4028 fprintf(stderr, "Failed to open file %s for writing\n",
4033 /* Write empty header first */
4034 ZERO_STRUCT(db_hdr);
4035 ret = write(fd, &db_hdr, sizeof(struct db_header));
4039 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4043 state.mem_ctx = mem_ctx;
4044 state.recbuf = NULL;
4049 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4051 fprintf(stderr, "Failed to collect records from DB %s\n",
4057 if (state.recbuf != NULL) {
4058 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4061 "Failed to write records to backup file\n");
4067 state.nrec += state.recbuf->count;
4068 TALLOC_FREE(state.recbuf);
4071 db_hdr.version = DB_VERSION;
4072 db_hdr.timestamp = time(NULL);
4073 db_hdr.flags = db_flags;
4074 db_hdr.nbuf = state.nbuf;
4075 db_hdr.nrec = state.nrec;
4076 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4078 lseek(fd, 0, SEEK_SET);
4079 ret = write(fd, &db_hdr, sizeof(struct db_header));
4083 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4088 printf("Database backed up to %s\n", argv[1]);
4092 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4093 int argc, const char **argv)
4095 const char *db_name = NULL;
4096 struct ctdb_db_context *db;
4097 struct db_header db_hdr;
4098 struct ctdb_node_map *nodemap;
4099 struct ctdb_req_control request;
4100 struct ctdb_reply_control **reply;
4101 struct ctdb_transdb wipedb;
4102 struct ctdb_pulldb_ext pulldb;
4103 struct ctdb_rec_buffer *recbuf;
4104 uint32_t generation;
4112 if (argc < 1 || argc > 2) {
4116 fd = open(argv[0], O_RDONLY, 0600);
4119 fprintf(stderr, "Failed to open file %s for reading\n",
4128 n = read(fd, &db_hdr, sizeof(struct db_header));
4132 fprintf(stderr, "Failed to read db header from file %s\n",
4136 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4138 if (db_hdr.version != DB_VERSION) {
4140 "Wrong version of backup file, expected %u, got %lu\n",
4141 DB_VERSION, db_hdr.version);
4146 if (db_name == NULL) {
4147 db_name = db_hdr.name;
4150 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4151 localtime(&db_hdr.timestamp));
4152 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4154 db_flags = db_hdr.flags & 0xff;
4155 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4158 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4163 nodemap = get_nodemap(ctdb, false);
4164 if (nodemap == NULL) {
4165 fprintf(stderr, "Failed to get nodemap\n");
4170 ret = get_generation(mem_ctx, ctdb, &generation);
4172 fprintf(stderr, "Failed to get current generation\n");
4177 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4184 wipedb.db_id = ctdb_db_id(db);
4185 wipedb.tid = generation;
4187 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4188 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4189 ctdb->client, pnn_list, count,
4190 TIMEOUT(), &request, NULL, NULL);
4196 ctdb_req_control_db_transaction_start(&request, &wipedb);
4197 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4198 pnn_list, count, TIMEOUT(),
4199 &request, NULL, NULL);
4204 ctdb_req_control_wipe_database(&request, &wipedb);
4205 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4206 pnn_list, count, TIMEOUT(),
4207 &request, NULL, NULL);
4212 pulldb.db_id = ctdb_db_id(db);
4214 pulldb.srvid = SRVID_CTDB_PUSHDB;
4216 ctdb_req_control_db_push_start(&request, &pulldb);
4217 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4218 pnn_list, count, TIMEOUT(),
4219 &request, NULL, NULL);
4224 for (i=0; i<db_hdr.nbuf; i++) {
4225 struct ctdb_req_message message;
4229 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4234 data.dsize = ctdb_rec_buffer_len(recbuf);
4235 data.dptr = talloc_size(mem_ctx, data.dsize);
4236 if (data.dptr == NULL) {
4240 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4242 message.srvid = pulldb.srvid;
4243 message.data.data = data;
4245 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4253 talloc_free(recbuf);
4254 talloc_free(data.dptr);
4257 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4258 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4259 pnn_list, count, TIMEOUT(),
4260 &request, NULL, &reply);
4265 for (i=0; i<count; i++) {
4266 uint32_t num_records;
4268 ret = ctdb_reply_control_db_push_confirm(reply[i],
4271 fprintf(stderr, "Invalid response from node %u\n",
4276 if (num_records != db_hdr.nrec) {
4277 fprintf(stderr, "Node %u received %u of %lu records\n",
4278 pnn_list[i], num_records, db_hdr.nrec);
4283 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4284 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4285 pnn_list, count, TIMEOUT(),
4286 &request, NULL, NULL);
4291 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4292 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4293 pnn_list, count, TIMEOUT(),
4294 &request, NULL, NULL);
4299 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4300 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4301 ctdb->client, pnn_list, count,
4302 TIMEOUT(), &request, NULL, NULL);
4307 printf("Database %s restored\n", db_name);
4314 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4315 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4319 struct dumpdbbackup_state {
4320 ctdb_rec_parser_func_t parser;
4321 struct dump_record_state sub_state;
4324 static int dumpdbbackup_handler(uint32_t reqid,
4325 struct ctdb_ltdb_header *header,
4326 TDB_DATA key, TDB_DATA data,
4329 struct dumpdbbackup_state *state =
4330 (struct dumpdbbackup_state *)private_data;
4331 struct ctdb_ltdb_header hdr;
4334 ret = ctdb_ltdb_header_extract(&data, &hdr);
4339 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4342 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4343 int argc, const char **argv)
4345 struct db_header db_hdr;
4347 struct dumpdbbackup_state state;
4352 usage("dumpbackup");
4355 fd = open(argv[0], O_RDONLY, 0600);
4358 fprintf(stderr, "Failed to open file %s for reading\n",
4363 n = read(fd, &db_hdr, sizeof(struct db_header));
4367 fprintf(stderr, "Failed to read db header from file %s\n",
4371 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4373 if (db_hdr.version != DB_VERSION) {
4375 "Wrong version of backup file, expected %u, got %lu\n",
4376 DB_VERSION, db_hdr.version);
4381 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4382 localtime(&db_hdr.timestamp));
4383 printf("Dumping database %s from backup @ %s\n",
4384 db_hdr.name, timebuf);
4386 state.parser = dump_record;
4387 state.sub_state.count = 0;
4389 for (i=0; i<db_hdr.nbuf; i++) {
4390 struct ctdb_rec_buffer *recbuf;
4392 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4394 fprintf(stderr, "Failed to read records\n");
4399 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4402 fprintf(stderr, "Failed to dump records\n");
4409 printf("Dumped %u record(s)\n", state.sub_state.count);
4413 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4414 int argc, const char **argv)
4416 const char *db_name;
4417 struct ctdb_db_context *db;
4420 struct ctdb_node_map *nodemap;
4421 struct ctdb_req_control request;
4422 struct ctdb_transdb wipedb;
4423 uint32_t generation;
4431 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4435 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4438 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4442 nodemap = get_nodemap(ctdb, false);
4443 if (nodemap == NULL) {
4444 fprintf(stderr, "Failed to get nodemap\n");
4448 ret = get_generation(mem_ctx, ctdb, &generation);
4450 fprintf(stderr, "Failed to get current generation\n");
4454 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4460 ctdb_req_control_db_freeze(&request, db_id);
4461 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4462 ctdb->client, pnn_list, count,
4463 TIMEOUT(), &request, NULL, NULL);
4468 wipedb.db_id = db_id;
4469 wipedb.tid = generation;
4471 ctdb_req_control_db_transaction_start(&request, &wipedb);
4472 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4473 pnn_list, count, TIMEOUT(),
4474 &request, NULL, NULL);
4479 ctdb_req_control_wipe_database(&request, &wipedb);
4480 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4481 pnn_list, count, TIMEOUT(),
4482 &request, NULL, NULL);
4487 ctdb_req_control_db_set_healthy(&request, db_id);
4488 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4489 pnn_list, count, TIMEOUT(),
4490 &request, NULL, NULL);
4495 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4496 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4497 pnn_list, count, TIMEOUT(),
4498 &request, NULL, NULL);
4503 ctdb_req_control_db_thaw(&request, db_id);
4504 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4505 ctdb->client, pnn_list, count,
4506 TIMEOUT(), &request, NULL, NULL);
4511 printf("Database %s wiped\n", db_name);
4516 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4517 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4521 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4522 int argc, const char **argv)
4527 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4528 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4533 printf("%u\n", recmaster);
4537 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4538 int argc, const char **argv)
4540 char *t, *event_helper = NULL;
4541 char *eventd_socket = NULL;
4542 const char **new_argv;
4545 t = getenv("CTDB_EVENT_HELPER");
4547 event_helper = talloc_strdup(mem_ctx, t);
4549 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb_event",
4550 CTDB_HELPER_BINDIR);
4553 if (event_helper == NULL) {
4554 fprintf(stderr, "Unable to set event daemon helper\n");
4558 t = getenv("CTDB_SOCKET");
4560 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4563 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4567 if (eventd_socket == NULL) {
4568 fprintf(stderr, "Unable to set event daemon socket\n");
4572 new_argv = talloc_array(mem_ctx, const char *, argc + 1);
4573 if (new_argv == NULL) {
4574 fprintf(stderr, "Memory allocation error\n");
4578 new_argv[0] = eventd_socket;
4579 for (i=0; i<argc; i++) {
4580 new_argv[i+1] = argv[i];
4583 return run_helper(mem_ctx, "event daemon helper", event_helper,
4587 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4588 int argc, const char **argv)
4590 const char *new_argv[3];
4593 usage("scriptstatus");
4596 new_argv[0] = "status";
4597 new_argv[1] = (argc == 0) ? "monitor" : argv[0];
4600 (void) control_event(mem_ctx, ctdb, 2, new_argv);
4604 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4605 int argc, const char **argv)
4607 char *t, *natgw_helper = NULL;
4613 t = getenv("CTDB_NATGW_HELPER");
4615 natgw_helper = talloc_strdup(mem_ctx, t);
4617 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4618 CTDB_HELPER_BINDIR);
4621 if (natgw_helper == NULL) {
4622 fprintf(stderr, "Unable to set NAT gateway helper\n");
4626 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4631 * Find the PNN of the current node
4632 * discover the pnn by loading the nodes file and try to bind
4633 * to all addresses one at a time until the ip address is found.
4635 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4637 struct ctdb_node_map *nodemap;
4640 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4641 if (nodemap == NULL) {
4645 for (i=0; i<nodemap->num; i++) {
4646 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4649 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4651 *pnn = nodemap->node[i].pnn;
4653 talloc_free(nodemap);
4658 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4659 talloc_free(nodemap);
4663 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4664 int argc, const char **argv)
4666 const char *reclock;
4670 usage("getreclock");
4673 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4674 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4679 if (reclock != NULL) {
4680 printf("%s\n", reclock);
4686 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4687 struct ctdb_context *ctdb,
4688 int argc, const char **argv)
4690 uint32_t lmasterrole = 0;
4694 usage("setlmasterrole");
4697 if (strcmp(argv[0], "on") == 0) {
4699 } else if (strcmp(argv[0], "off") == 0) {
4702 usage("setlmasterrole");
4705 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4706 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4714 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4715 struct ctdb_context *ctdb,
4716 int argc, const char **argv)
4718 uint32_t recmasterrole = 0;
4722 usage("setrecmasterrole");
4725 if (strcmp(argv[0], "on") == 0) {
4727 } else if (strcmp(argv[0], "off") == 0) {
4730 usage("setrecmasterrole");
4733 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4734 ctdb->cmd_pnn, TIMEOUT(),
4743 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4744 struct ctdb_context *ctdb,
4745 int argc, const char **argv)
4752 usage("setdbreadonly");
4755 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4759 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4760 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4764 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4765 ctdb->cmd_pnn, TIMEOUT(), db_id);
4773 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4774 int argc, const char **argv)
4781 usage("setdbsticky");
4784 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4788 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4789 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4793 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4794 ctdb->cmd_pnn, TIMEOUT(), db_id);
4802 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4803 int argc, const char **argv)
4805 const char *db_name;
4806 struct ctdb_db_context *db;
4807 struct ctdb_transaction_handle *h;
4812 if (argc < 2 || argc > 3) {
4816 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4821 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4822 fprintf(stderr, "Transactions not supported on DB %s\n",
4827 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4830 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4834 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4836 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4840 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4841 TIMEOUT(), db, true, &h);
4843 fprintf(stderr, "Failed to start transaction on db %s\n",
4848 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4850 fprintf(stderr, "Failed to read record for key %s\n",
4852 ctdb_transaction_cancel(h);
4856 printf("%.*s\n", (int)data.dsize, data.dptr);
4858 ctdb_transaction_cancel(h);
4862 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4863 int argc, const char **argv)
4865 const char *db_name;
4866 struct ctdb_db_context *db;
4867 struct ctdb_transaction_handle *h;
4876 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4881 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4882 fprintf(stderr, "Transactions not supported on DB %s\n",
4887 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4890 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4894 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4896 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4900 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4902 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4906 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4907 TIMEOUT(), db, false, &h);
4909 fprintf(stderr, "Failed to start transaction on db %s\n",
4914 ret = ctdb_transaction_store_record(h, key, data);
4916 fprintf(stderr, "Failed to store record for key %s\n",
4918 ctdb_transaction_cancel(h);
4922 ret = ctdb_transaction_commit(h);
4924 fprintf(stderr, "Failed to commit transaction on db %s\n",
4926 ctdb_transaction_cancel(h);
4933 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4934 int argc, const char **argv)
4936 const char *db_name;
4937 struct ctdb_db_context *db;
4938 struct ctdb_transaction_handle *h;
4947 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4952 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4953 fprintf(stderr, "Transactions not supported on DB %s\n",
4958 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4961 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4965 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4967 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4971 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4972 TIMEOUT(), db, false, &h);
4974 fprintf(stderr, "Failed to start transaction on db %s\n",
4979 ret = ctdb_transaction_delete_record(h, key);
4981 fprintf(stderr, "Failed to delete record for key %s\n",
4983 ctdb_transaction_cancel(h);
4987 ret = ctdb_transaction_commit(h);
4989 fprintf(stderr, "Failed to commit transaction on db %s\n",
4991 ctdb_transaction_cancel(h);
4998 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5006 /* Skip whitespace */
5007 n = strspn(*ptr, " \t");
5011 /* Quoted ASCII string - no wide characters! */
5013 n = strcspn(t, "\"");
5016 ret = str_to_data(t, n, mem_ctx, data);
5023 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5027 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5034 #define MAX_LINE_SIZE 1024
5036 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5037 TDB_DATA *key, TDB_DATA *value)
5039 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5043 ptr = fgets(line, MAX_LINE_SIZE, file);
5049 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5050 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5051 /* Line Ignored but not EOF */
5057 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5059 /* Line Ignored but not EOF */
5060 talloc_free(key->dptr);
5068 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5069 int argc, const char **argv)
5071 const char *db_name;
5072 struct ctdb_db_context *db;
5073 struct ctdb_transaction_handle *h;
5076 TDB_DATA key, value;
5079 if (argc < 1 || argc > 2) {
5083 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5088 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5089 fprintf(stderr, "Transactions not supported on DB %s\n",
5095 file = fopen(argv[1], "r");
5097 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5104 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5107 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5111 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5112 TIMEOUT(), db, false, &h);
5114 fprintf(stderr, "Failed to start transaction on db %s\n",
5119 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5120 if (key.dsize != 0) {
5121 ret = ctdb_transaction_store_record(h, key, value);
5123 fprintf(stderr, "Failed to store record\n");
5124 ctdb_transaction_cancel(h);
5127 talloc_free(key.dptr);
5128 talloc_free(value.dptr);
5132 ret = ctdb_transaction_commit(h);
5134 fprintf(stderr, "Failed to commit transaction on db %s\n",
5136 ctdb_transaction_cancel(h);
5140 if (file != stdin) {
5146 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5147 int argc, const char **argv)
5149 struct tdb_context *tdb;
5151 struct ctdb_ltdb_header header;
5154 if (argc < 2 || argc > 3) {
5158 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5160 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5164 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5166 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5171 data = tdb_fetch(tdb, key);
5172 if (data.dptr == NULL) {
5173 fprintf(stderr, "No record for key %s\n", argv[1]);
5178 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5179 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5190 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5192 fprintf(stderr, "Failed to open output file %s\n",
5197 nwritten = sys_write(fd, data.dptr, data.dsize);
5198 if (nwritten != data.dsize) {
5199 fprintf(stderr, "Failed to write record to file\n");
5208 ret = ctdb_ltdb_header_extract(&data, &header);
5210 fprintf(stderr, "Failed to parse header from data\n");
5214 dump_ltdb_header(&header);
5215 dump_tdb_data("data", data);
5220 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5221 int argc, const char **argv)
5223 struct tdb_context *tdb;
5224 TDB_DATA key, data[2], value;
5225 struct ctdb_ltdb_header header;
5226 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5230 if (argc < 3 || argc > 5) {
5234 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5236 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5240 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5242 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5247 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5249 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5254 ZERO_STRUCT(header);
5257 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5260 header.dmaster = (uint32_t)atol(argv[4]);
5263 header.flags = (uint32_t)atol(argv[5]);
5266 ctdb_ltdb_header_push(&header, header_buf, &np);
5269 data[0].dptr = header_buf;
5271 data[1].dsize = value.dsize;
5272 data[1].dptr = value.dptr;
5274 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5276 fprintf(stderr, "Failed to write record %s to file %s\n",
5285 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5286 int argc, const char **argv)
5288 const char *db_name;
5289 struct ctdb_db_context *db;
5290 struct ctdb_record_handle *h;
5293 bool readonly = false;
5296 if (argc < 2 || argc > 3) {
5301 if (strcmp(argv[2], "readonly") == 0) {
5308 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5312 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5313 fprintf(stderr, "DB %s is not a volatile database\n",
5318 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5321 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5325 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5327 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5331 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5332 db, key, readonly, &h, NULL, &data);
5334 fprintf(stderr, "Failed to read record for key %s\n",
5337 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5338 (int)data.dsize, data.dptr);
5345 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5346 int argc, const char **argv)
5348 const char *db_name;
5349 struct ctdb_db_context *db;
5350 struct ctdb_record_handle *h;
5359 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5363 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5364 fprintf(stderr, "DB %s is not a volatile database\n",
5369 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5372 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5376 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5378 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5382 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5384 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5388 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5389 db, key, false, &h, NULL, NULL);
5391 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5395 ret = ctdb_store_record(h, data);
5397 fprintf(stderr, "Failed to store record for key %s\n",
5405 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5406 int argc, const char **argv)
5408 const char *db_name;
5409 struct ctdb_db_context *db;
5410 struct ctdb_record_handle *h;
5419 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5423 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5424 fprintf(stderr, "DB %s is not a volatile database\n",
5429 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5432 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5436 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5438 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5442 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5443 db, key, false, &h, NULL, &data);
5445 fprintf(stderr, "Failed to fetch record for key %s\n",
5450 ret = ctdb_delete_record(h);
5452 fprintf(stderr, "Failed to delete record for key %s\n",
5460 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5461 int argc, const char **argv)
5463 struct sockaddr_in sin;
5469 usage("chktcpport");
5472 port = atoi(argv[0]);
5474 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5476 fprintf(stderr, "Failed to open local socket\n");
5480 v = fcntl(s, F_GETFL, 0);
5481 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5482 fprintf(stderr, "Unable to set socket non-blocking\n");
5487 bzero(&sin, sizeof(sin));
5488 sin.sin_family = AF_INET;
5489 sin.sin_port = htons(port);
5490 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5493 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5500 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5501 int argc, const char **argv)
5504 const char *db_name;
5509 usage("getdbseqnum");
5512 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5516 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5517 ctdb->cmd_pnn, TIMEOUT(), db_id,
5520 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5525 printf("0x%"PRIx64"\n", seqnum);
5529 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5530 int argc, const char **argv)
5532 const char *nodestring = NULL;
5533 struct ctdb_node_map *nodemap;
5535 bool print_hdr = false;
5538 usage("nodestatus");
5542 nodestring = argv[0];
5543 if (strcmp(nodestring, "all") == 0) {
5548 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5552 if (options.machinereadable) {
5553 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5555 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5559 for (i=0; i<nodemap->num; i++) {
5560 ret |= nodemap->node[i].flags;
5569 } db_stats_fields[] = {
5570 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5571 DBSTATISTICS_FIELD(db_ro_delegations),
5572 DBSTATISTICS_FIELD(db_ro_revokes),
5573 DBSTATISTICS_FIELD(locks.num_calls),
5574 DBSTATISTICS_FIELD(locks.num_current),
5575 DBSTATISTICS_FIELD(locks.num_pending),
5576 DBSTATISTICS_FIELD(locks.num_failed),
5577 DBSTATISTICS_FIELD(db_ro_delegations),
5580 static void print_dbstatistics(const char *db_name,
5581 struct ctdb_db_statistics *s)
5584 const char *prefix = NULL;
5587 printf("DB Statistics %s\n", db_name);
5589 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5590 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5591 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5593 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5594 prefix = db_stats_fields[i].name;
5595 printf(" %*.*s\n", preflen-1, preflen-1,
5596 db_stats_fields[i].name);
5601 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5602 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5603 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5606 printf(" hop_count_buckets:");
5607 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5608 printf(" %d", s->hop_count_bucket[i]);
5612 printf(" lock_buckets:");
5613 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5614 printf(" %d", s->locks.buckets[i]);
5618 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5619 "locks_latency MIN/AVG/MAX",
5620 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5621 s->locks.latency.max, s->locks.latency.num);
5623 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5624 "vacuum_latency MIN/AVG/MAX",
5625 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5626 s->vacuum.latency.max, s->vacuum.latency.num);
5628 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5629 for (i=0; i<s->num_hot_keys; i++) {
5631 printf(" Count:%d Key:", s->hot_keys[i].count);
5632 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5633 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5639 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5640 int argc, const char **argv)
5643 const char *db_name;
5644 struct ctdb_db_statistics *dbstats;
5648 usage("dbstatistics");
5651 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5655 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5656 ctdb->cmd_pnn, TIMEOUT(), db_id,
5659 fprintf(stderr, "Failed to get statistics for DB %s\n",
5664 print_dbstatistics(db_name, dbstats);
5668 struct disable_takeover_runs_state {
5676 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5679 struct disable_takeover_runs_state *state =
5680 (struct disable_takeover_runs_state *)private_data;
5683 if (data.dsize != sizeof(int)) {
5688 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5689 ret = *(int *)data.dptr;
5691 state->status = ret;
5695 for (i=0; i<state->node_count; i++) {
5696 if (state->pnn_list[i] == ret) {
5697 state->reply[i] = true;
5703 for (i=0; i<state->node_count; i++) {
5704 if (! state->reply[i]) {
5705 state->done = false;
5711 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5712 struct ctdb_context *ctdb, uint32_t timeout,
5713 uint32_t *pnn_list, int count)
5715 struct ctdb_disable_message disable = { 0 };
5716 struct disable_takeover_runs_state state;
5719 disable.pnn = ctdb->pnn;
5720 disable.srvid = next_srvid(ctdb);
5721 disable.timeout = timeout;
5723 state.pnn_list = pnn_list;
5724 state.node_count = count;
5727 state.reply = talloc_zero_array(mem_ctx, bool, count);
5728 if (state.reply == NULL) {
5732 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5734 disable_takeover_run_handler,
5740 for (i=0; i<count; i++) {
5741 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5750 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5752 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5754 ret = (state.status >= 0 ? 0 : 1);
5758 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5759 disable.srvid, &state);
5763 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5764 int argc, const char **argv)
5766 const char *nodestring = NULL;
5767 struct ctdb_node_map *nodemap, *nodemap2;
5768 struct ctdb_req_control request;
5769 uint32_t *pnn_list, *pnn_list2;
5770 int ret, count, count2;
5777 nodestring = argv[0];
5780 nodemap = get_nodemap(ctdb, false);
5781 if (nodemap == NULL) {
5785 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5789 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5790 mem_ctx, &pnn_list);
5792 fprintf(stderr, "Memory allocation error\n");
5796 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5797 mem_ctx, &pnn_list2);
5799 fprintf(stderr, "Memory allocation error\n");
5803 /* Disable takeover runs on all connected nodes. A reply
5804 * indicating success is needed from each node so all nodes
5805 * will need to be active.
5807 * A check could be added to not allow reloading of IPs when
5808 * there are disconnected nodes. However, this should
5809 * probably be left up to the administrator.
5811 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5814 fprintf(stderr, "Failed to disable takeover runs\n");
5818 /* Now tell all the desired nodes to reload their public IPs.
5819 * Keep trying this until it succeeds. This assumes all
5820 * failures are transient, which might not be true...
5822 ctdb_req_control_reload_public_ips(&request);
5823 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5824 pnn_list2, count2, TIMEOUT(),
5825 &request, NULL, NULL);
5827 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5830 /* It isn't strictly necessary to wait until takeover runs are
5831 * re-enabled but doing so can't hurt.
5833 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5835 fprintf(stderr, "Failed to enable takeover runs\n");
5839 return ipreallocate(mem_ctx, ctdb);
5842 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5843 int argc, const char **argv)
5845 ctdb_sock_addr addr;
5852 if (! parse_ip(argv[0], NULL, 0, &addr)) {
5853 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
5857 iface = ctdb_sys_find_ifname(&addr);
5858 if (iface == NULL) {
5859 fprintf(stderr, "Failed to find interface for IP %s\n",
5869 static const struct ctdb_cmd {
5871 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5872 bool without_daemon; /* can be run without daemon running ? */
5873 bool remote; /* can be run on remote nodes */
5876 } ctdb_commands[] = {
5877 { "version", control_version, true, false,
5878 "show version of ctdb", NULL },
5879 { "status", control_status, false, true,
5880 "show node status", NULL },
5881 { "uptime", control_uptime, false, true,
5882 "show node uptime", NULL },
5883 { "ping", control_ping, false, true,
5884 "ping all nodes", NULL },
5885 { "runstate", control_runstate, false, true,
5886 "get/check runstate of a node",
5887 "[setup|first_recovery|startup|running]" },
5888 { "getvar", control_getvar, false, true,
5889 "get a tunable variable", "<name>" },
5890 { "setvar", control_setvar, false, true,
5891 "set a tunable variable", "<name> <value>" },
5892 { "listvars", control_listvars, false, true,
5893 "list tunable variables", NULL },
5894 { "statistics", control_statistics, false, true,
5895 "show ctdb statistics", NULL },
5896 { "statisticsreset", control_statistics_reset, false, true,
5897 "reset ctdb statistics", NULL },
5898 { "stats", control_stats, false, true,
5899 "show rolling statistics", "[count]" },
5900 { "ip", control_ip, false, true,
5901 "show public ips", "[all]" },
5902 { "ipinfo", control_ipinfo, false, true,
5903 "show public ip details", "<ip>" },
5904 { "ifaces", control_ifaces, false, true,
5905 "show interfaces", NULL },
5906 { "setifacelink", control_setifacelink, false, true,
5907 "set interface link status", "<iface> up|down" },
5908 { "process-exists", control_process_exists, false, true,
5909 "check if a process exists on a node", "<pid> [<srvid>]" },
5910 { "getdbmap", control_getdbmap, false, true,
5911 "show attached databases", NULL },
5912 { "getdbstatus", control_getdbstatus, false, true,
5913 "show database status", "<dbname|dbid>" },
5914 { "catdb", control_catdb, false, false,
5915 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5916 { "cattdb", control_cattdb, false, false,
5917 "dump local ctdb database", "<dbname|dbid>" },
5918 { "getcapabilities", control_getcapabilities, false, true,
5919 "show node capabilities", NULL },
5920 { "pnn", control_pnn, false, false,
5921 "show the pnn of the currnet node", NULL },
5922 { "lvs", control_lvs, false, false,
5923 "show lvs configuration", "master|list|status" },
5924 { "setdebug", control_setdebug, false, true,
5925 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5926 { "getdebug", control_getdebug, false, true,
5927 "get debug level", NULL },
5928 { "attach", control_attach, false, false,
5929 "attach a database", "<dbname> [persistent|replicated]" },
5930 { "detach", control_detach, false, false,
5931 "detach database(s)", "<dbname|dbid> ..." },
5932 { "dumpmemory", control_dumpmemory, false, true,
5933 "dump ctdbd memory map", NULL },
5934 { "rddumpmemory", control_rddumpmemory, false, true,
5935 "dump recoverd memory map", NULL },
5936 { "getpid", control_getpid, false, true,
5937 "get ctdbd process ID", NULL },
5938 { "disable", control_disable, false, true,
5939 "disable a node", NULL },
5940 { "enable", control_enable, false, true,
5941 "enable a node", NULL },
5942 { "stop", control_stop, false, true,
5943 "stop a node", NULL },
5944 { "continue", control_continue, false, true,
5945 "continue a stopped node", NULL },
5946 { "ban", control_ban, false, true,
5947 "ban a node", "<bantime>"},
5948 { "unban", control_unban, false, true,
5949 "unban a node", NULL },
5950 { "shutdown", control_shutdown, false, true,
5951 "shutdown ctdb daemon", NULL },
5952 { "recover", control_recover, false, true,
5953 "force recovery", NULL },
5954 { "sync", control_ipreallocate, false, true,
5955 "run ip reallocation (deprecated)", NULL },
5956 { "ipreallocate", control_ipreallocate, false, true,
5957 "run ip reallocation", NULL },
5958 { "isnotrecmaster", control_isnotrecmaster, false, false,
5959 "check if local node is the recmaster", NULL },
5960 { "gratarp", control_gratarp, false, true,
5961 "send a gratuitous arp", "<ip> <interface>" },
5962 { "tickle", control_tickle, true, false,
5963 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5964 { "gettickles", control_gettickles, false, true,
5965 "get the list of tickles", "<ip> [<port>]" },
5966 { "addtickle", control_addtickle, false, true,
5967 "add a tickle", "<ip>:<port> <ip>:<port>" },
5968 { "deltickle", control_deltickle, false, true,
5969 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5970 { "listnodes", control_listnodes, true, true,
5971 "list nodes in the cluster", NULL },
5972 { "reloadnodes", control_reloadnodes, false, false,
5973 "reload the nodes file all nodes", NULL },
5974 { "moveip", control_moveip, false, false,
5975 "move an ip address to another node", "<ip> <node>" },
5976 { "addip", control_addip, false, true,
5977 "add an ip address to a node", "<ip/mask> <iface>" },
5978 { "delip", control_delip, false, true,
5979 "delete an ip address from a node", "<ip>" },
5980 { "backupdb", control_backupdb, false, false,
5981 "backup a database into a file", "<dbname|dbid> <file>" },
5982 { "restoredb", control_restoredb, false, false,
5983 "restore a database from a file", "<file> [dbname]" },
5984 { "dumpdbbackup", control_dumpdbbackup, true, false,
5985 "dump database from a backup file", "<file>" },
5986 { "wipedb", control_wipedb, false, false,
5987 "wipe the contents of a database.", "<dbname|dbid>"},
5988 { "recmaster", control_recmaster, false, true,
5989 "show the pnn for the recovery master", NULL },
5990 { "event", control_event, true, false,
5991 "event and event script commands", NULL },
5992 { "scriptstatus", control_scriptstatus, true, false,
5993 "show event script status",
5994 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5995 { "natgw", control_natgw, false, false,
5996 "show natgw configuration", "master|list|status" },
5997 { "getreclock", control_getreclock, false, true,
5998 "get recovery lock file", NULL },
5999 { "setlmasterrole", control_setlmasterrole, false, true,
6000 "set LMASTER role", "on|off" },
6001 { "setrecmasterrole", control_setrecmasterrole, false, true,
6002 "set RECMASTER role", "on|off"},
6003 { "setdbreadonly", control_setdbreadonly, false, true,
6004 "enable readonly records", "<dbname|dbid>" },
6005 { "setdbsticky", control_setdbsticky, false, true,
6006 "enable sticky records", "<dbname|dbid>"},
6007 { "pfetch", control_pfetch, false, false,
6008 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6009 { "pstore", control_pstore, false, false,
6010 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6011 { "pdelete", control_pdelete, false, false,
6012 "delete record from persistent database", "<dbname|dbid> <key>" },
6013 { "ptrans", control_ptrans, false, false,
6014 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6015 { "tfetch", control_tfetch, false, true,
6016 "fetch a record", "<tdb-file> <key> [<file>]" },
6017 { "tstore", control_tstore, false, true,
6018 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6019 { "readkey", control_readkey, false, false,
6020 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6021 { "writekey", control_writekey, false, false,
6022 "write value for a database key", "<dbname|dbid> <key> <value>" },
6023 { "deletekey", control_deletekey, false, false,
6024 "delete a database key", "<dbname|dbid> <key>" },
6025 { "checktcpport", control_checktcpport, true, false,
6026 "check if a service is bound to a specific tcp port or not", "<port>" },
6027 { "getdbseqnum", control_getdbseqnum, false, false,
6028 "get database sequence number", "<dbname|dbid>" },
6029 { "nodestatus", control_nodestatus, false, true,
6030 "show and return node status", "[all|<pnn-list>]" },
6031 { "dbstatistics", control_dbstatistics, false, true,
6032 "show database statistics", "<dbname|dbid>" },
6033 { "reloadips", control_reloadips, false, false,
6034 "reload the public addresses file", "[all|<pnn-list>]" },
6035 { "ipiface", control_ipiface, true, false,
6036 "Find the interface an ip address is hosted on", "<ip>" },
6039 static const struct ctdb_cmd *match_command(const char *command)
6041 const struct ctdb_cmd *cmd;
6044 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6045 cmd = &ctdb_commands[i];
6046 if (strlen(command) == strlen(cmd->name) &&
6047 strncmp(command, cmd->name, strlen(command)) == 0) {
6057 * Show usage message
6059 static void usage_full(void)
6063 poptPrintHelp(pc, stdout, 0);
6064 printf("\nCommands:\n");
6065 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6066 printf(" %-15s %-27s %s\n",
6067 ctdb_commands[i].name,
6068 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6069 ctdb_commands[i].msg);
6073 static void usage(const char *command)
6075 const struct ctdb_cmd *cmd;
6077 if (command == NULL) {
6082 cmd = match_command(command);
6086 poptPrintUsage(pc, stdout, 0);
6087 printf("\nCommands:\n");
6088 printf(" %-15s %-27s %s\n",
6089 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6095 struct poptOption cmdline_options[] = {
6097 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6098 "CTDB socket path", "filename" },
6099 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6101 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6102 "timelimit (in seconds)" },
6103 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6104 "node specification - integer" },
6105 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6106 "enable machine readable output", NULL },
6107 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6108 "specify separator for machine readable output", "CHAR" },
6109 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6110 "enable machine parsable output with separator |", NULL },
6111 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6112 "enable verbose output", NULL },
6113 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6114 "die if runtime exceeds this limit (in seconds)" },
6118 static int process_command(const struct ctdb_cmd *cmd, int argc,
6121 TALLOC_CTX *tmp_ctx;
6122 struct ctdb_context *ctdb;
6125 uint64_t srvid_offset;
6127 tmp_ctx = talloc_new(NULL);
6128 if (tmp_ctx == NULL) {
6129 fprintf(stderr, "Memory allocation error\n");
6133 if (cmd->without_daemon) {
6134 if (options.pnn != -1) {
6136 "Cannot specify node for command %s\n",
6141 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6142 talloc_free(tmp_ctx);
6146 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6148 fprintf(stderr, "Memory allocation error\n");
6152 ctdb->ev = tevent_context_init(ctdb);
6153 if (ctdb->ev == NULL) {
6154 fprintf(stderr, "Failed to initialize tevent\n");
6158 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6160 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6163 if (!find_node_xpnn(ctdb, NULL)) {
6164 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6169 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6170 srvid_offset = getpid() & 0xFFFF;
6171 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6173 if (options.pnn != -1) {
6174 status = verify_pnn(ctdb, options.pnn);
6179 ctdb->cmd_pnn = options.pnn;
6181 ctdb->cmd_pnn = ctdb->pnn;
6184 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6185 fprintf(stderr, "Node cannot be specified for command %s\n",
6190 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6191 talloc_free(tmp_ctx);
6195 talloc_free(tmp_ctx);
6199 static void signal_handler(int sig)
6201 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6204 static void alarm_handler(int sig)
6206 /* Kill any child processes */
6207 signal(SIGTERM, signal_handler);
6213 int main(int argc, const char *argv[])
6216 const char **extra_argv;
6218 const struct ctdb_cmd *cmd;
6219 const char *ctdb_socket;
6225 /* Set default options */
6226 options.socket = CTDB_SOCKET;
6227 options.debuglevelstr = NULL;
6228 options.timelimit = 10;
6230 options.maxruntime = 0;
6233 ctdb_socket = getenv("CTDB_SOCKET");
6234 if (ctdb_socket != NULL) {
6235 options.socket = ctdb_socket;
6238 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6239 POPT_CONTEXT_KEEP_FIRST);
6240 while ((opt = poptGetNextOpt(pc)) != -1) {
6241 fprintf(stderr, "Invalid option %s: %s\n",
6242 poptBadOption(pc, 0), poptStrerror(opt));
6246 if (options.maxruntime == 0) {
6247 const char *ctdb_timeout;
6249 ctdb_timeout = getenv("CTDB_TIMEOUT");
6250 if (ctdb_timeout != NULL) {
6251 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6253 options.maxruntime = 120;
6256 if (options.maxruntime <= 120) {
6257 /* default timeout is 120 seconds */
6258 options.maxruntime = 120;
6261 if (options.machineparsable) {
6262 options.machinereadable = 1;
6265 /* setup the remaining options for the commands */
6267 extra_argv = poptGetArgs(pc);
6270 while (extra_argv[extra_argc]) extra_argc++;
6273 if (extra_argc < 1) {
6277 cmd = match_command(extra_argv[0]);
6279 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6283 /* Enable logging */
6284 setup_logging("ctdb", DEBUG_STDERR);
6285 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6286 DEBUGLEVEL = loglevel;
6288 DEBUGLEVEL = DEBUG_ERR;
6291 signal(SIGALRM, alarm_handler);
6292 alarm(options.maxruntime);
6294 ret = process_command(cmd, extra_argc, extra_argv);
6299 (void)poptFreeContext(pc);