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"
32 #include "ctdb_version.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
35 #include "lib/util/sys_rw.h"
37 #include "common/db_hash.h"
38 #include "common/logging.h"
39 #include "protocol/protocol.h"
40 #include "protocol/protocol_api.h"
41 #include "common/system.h"
42 #include "client/client.h"
44 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
46 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
47 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
51 const char *debuglevelstr;
59 int printemptyrecords;
66 static poptContext pc;
69 struct tevent_context *ev;
70 struct ctdb_client_context *client;
71 struct ctdb_node_map *nodemap;
72 uint32_t pnn, cmd_pnn;
76 static void usage(const char *command);
82 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
84 return (tv2->tv_sec - tv->tv_sec) +
85 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
88 static struct ctdb_node_and_flags *get_node_by_pnn(
89 struct ctdb_node_map *nodemap,
94 for (i=0; i<nodemap->num; i++) {
95 if (nodemap->node[i].pnn == pnn) {
96 return &nodemap->node[i];
102 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
104 static const struct {
108 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
109 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
110 { NODE_FLAGS_BANNED, "BANNED" },
111 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
112 { NODE_FLAGS_DELETED, "DELETED" },
113 { NODE_FLAGS_STOPPED, "STOPPED" },
114 { NODE_FLAGS_INACTIVE, "INACTIVE" },
116 char *flags_str = NULL;
119 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
120 if (flags & flag_names[i].flag) {
121 if (flags_str == NULL) {
122 flags_str = talloc_asprintf(mem_ctx,
123 "%s", flag_names[i].name);
125 flags_str = talloc_asprintf_append(flags_str,
126 "|%s", flag_names[i].name);
128 if (flags_str == NULL) {
129 return "OUT-OF-MEMORY";
133 if (flags_str == NULL) {
140 static uint64_t next_srvid(struct ctdb_context *ctdb)
147 * Get consistent nodemap information.
149 * If nodemap is already cached, use that. If not get it.
150 * If the current node is BANNED, then get nodemap from "better" node.
152 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
155 struct ctdb_node_map *nodemap;
156 struct ctdb_node_and_flags *node;
157 uint32_t current_node;
161 TALLOC_FREE(ctdb->nodemap);
164 if (ctdb->nodemap != NULL) {
165 return ctdb->nodemap;
168 tmp_ctx = talloc_new(ctdb);
169 if (tmp_ctx == NULL) {
173 current_node = ctdb->pnn;
175 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
176 current_node, TIMEOUT(), &nodemap);
178 fprintf(stderr, "Failed to get nodemap from node %u\n",
183 node = get_node_by_pnn(nodemap, current_node);
184 if (node->flags & NODE_FLAGS_BANNED) {
187 current_node = (current_node + 1) % nodemap->num;
188 node = get_node_by_pnn(nodemap, current_node);
190 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
193 } while (current_node != ctdb->pnn);
195 if (current_node == ctdb->pnn) {
196 /* Tried all nodes in the cluster */
197 fprintf(stderr, "Warning: All nodes are banned.\n");
204 ctdb->nodemap = talloc_steal(ctdb, nodemap);
208 talloc_free(tmp_ctx);
212 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
214 struct ctdb_node_map *nodemap;
222 nodemap = get_nodemap(ctdb, false);
223 if (nodemap == NULL) {
228 for (i=0; i<nodemap->num; i++) {
229 if (nodemap->node[i].pnn == pnn) {
235 fprintf(stderr, "Node %u does not exist\n", pnn);
239 if (nodemap->node[i].flags &
240 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
241 fprintf(stderr, "Node %u has status %s\n", pnn,
242 pretty_print_flags(ctdb, nodemap->node[i].flags));
249 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
250 struct ctdb_node_map *nodemap)
252 struct ctdb_node_map *nodemap2;
254 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
255 if (nodemap2 == NULL) {
259 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
261 if (nodemap2->node == NULL) {
262 talloc_free(nodemap2);
270 * Get the number and the list of matching nodes
272 * nodestring := NULL | all | pnn,[pnn,...]
274 * If nodestring is NULL, use the current node.
276 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
277 const char *nodestring,
278 struct ctdb_node_map **out)
280 struct ctdb_node_map *nodemap, *nodemap2;
281 struct ctdb_node_and_flags *node;
284 nodemap = get_nodemap(ctdb, false);
285 if (nodemap == NULL) {
289 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
290 if (nodemap2 == NULL) {
294 if (nodestring == NULL) {
295 for (i=0; i<nodemap->num; i++) {
296 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
297 nodemap2->node[0] = nodemap->node[i];
306 if (strcmp(nodestring, "all") == 0) {
307 for (i=0; i<nodemap->num; i++) {
308 nodemap2->node[i] = nodemap->node[i];
310 nodemap2->num = nodemap->num;
316 ns = talloc_strdup(mem_ctx, nodestring);
321 tok = strtok(ns, ",");
322 while (tok != NULL) {
326 pnn = (uint32_t)strtoul(tok, &endptr, 0);
327 if (pnn == 0 && tok == endptr) {
328 fprintf(stderr, "Invalid node %s\n", tok);
332 node = get_node_by_pnn(nodemap, pnn);
334 fprintf(stderr, "Node %u does not exist\n",
339 nodemap2->node[nodemap2->num] = *node;
342 tok = strtok(NULL, ",");
351 /* Compare IP address */
352 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
356 if (ip1->sa.sa_family != ip2->sa.sa_family) {
360 switch (ip1->sa.sa_family) {
362 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
363 sizeof(struct in_addr)) == 0);
367 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
368 sizeof(struct in6_addr)) == 0);
375 /* Append a node to a node map with given address and flags */
376 static bool node_map_add(struct ctdb_node_map *nodemap,
377 const char *nstr, uint32_t flags)
381 struct ctdb_node_and_flags *n;
383 if (! parse_ip(nstr, NULL, 0, &addr)) {
384 fprintf(stderr, "Invalid IP address %s\n", nstr);
389 nodemap->node = talloc_realloc(nodemap, nodemap->node,
390 struct ctdb_node_and_flags, num+1);
391 if (nodemap->node == NULL) {
395 n = &nodemap->node[num];
400 nodemap->num = num+1;
404 /* Read a nodes file into a node map */
405 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
411 struct ctdb_node_map *nodemap;
413 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
414 if (nodemap == NULL) {
418 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
423 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
427 for (i=0; i<nlines; i++) {
433 /* strip leading spaces */
434 while((*node == ' ') || (*node == '\t')) {
440 /* strip trailing spaces */
442 ((node[len-1] == ' ') || (node[len-1] == '\t')))
452 /* A "deleted" node is a node that is
453 commented out in the nodes file. This is
454 used instead of removing a line, which
455 would cause subsequent nodes to change
457 flags = NODE_FLAGS_DELETED;
458 node = discard_const("0.0.0.0");
462 if (! node_map_add(nodemap, node, flags)) {
464 TALLOC_FREE(nodemap);
473 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
475 struct ctdb_node_map *nodemap;
477 const char *nodes_list = NULL;
479 if (pnn != CTDB_UNKNOWN_PNN) {
480 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
481 if (nodepath != NULL) {
482 nodes_list = getenv(nodepath);
485 if (nodes_list == NULL) {
486 nodes_list = getenv("CTDB_NODES");
488 if (nodes_list == NULL) {
489 const char *basedir = getenv("CTDB_BASE");
490 if (basedir == NULL) {
491 basedir = CTDB_ETCDIR;
493 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
494 if (nodes_list == NULL) {
495 fprintf(stderr, "Memory allocation error\n");
500 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
501 if (nodemap == NULL) {
502 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
510 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
511 struct ctdb_context *ctdb,
512 struct ctdb_dbid_map *dbmap,
515 struct ctdb_dbid *db = NULL;
519 for (i=0; i<dbmap->num; i++) {
520 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
521 ctdb->pnn, TIMEOUT(),
522 dbmap->dbs[i].db_id, &name);
527 if (strcmp(db_name, name) == 0) {
528 talloc_free(discard_const(name));
537 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
538 const char *db_arg, uint32_t *db_id,
539 const char **db_name, uint8_t *db_flags)
541 struct ctdb_dbid_map *dbmap;
542 struct ctdb_dbid *db = NULL;
544 const char *name = NULL;
547 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
548 ctdb->pnn, TIMEOUT(), &dbmap);
553 if (strncmp(db_arg, "0x", 2) == 0) {
554 id = strtoul(db_arg, NULL, 0);
555 for (i=0; i<dbmap->num; i++) {
556 if (id == dbmap->dbs[i].db_id) {
563 db = db_find(mem_ctx, ctdb, dbmap, name);
567 fprintf(stderr, "No database matching '%s' found\n", db_arg);
572 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
573 ctdb->pnn, TIMEOUT(), id, &name);
582 if (db_name != NULL) {
583 *db_name = talloc_strdup(mem_ctx, name);
585 if (db_flags != NULL) {
586 *db_flags = db->flags;
591 static int h2i(char h)
593 if (h >= 'a' && h <= 'f') {
596 if (h >= 'A' && h <= 'F') {
602 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
609 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
614 data.dsize = len / 2;
615 data.dptr = talloc_size(mem_ctx, data.dsize);
616 if (data.dptr == NULL) {
620 for (i=0; i<data.dsize; i++) {
621 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
628 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
634 if (strncmp(str, "0x", 2) == 0) {
635 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
637 data.dptr = talloc_memdup(mem_ctx, str, len);
638 if (data.dptr == NULL) {
648 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
649 const char *path, int argc, const char **argv)
652 int save_errno, status, ret;
653 const char **new_argv;
656 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
657 if (new_argv == NULL) {
662 for (i=0; i<argc; i++) {
663 new_argv[i+1] = argv[i];
665 new_argv[argc+1] = NULL;
670 talloc_free(new_argv);
671 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
672 command, path, strerror(save_errno));
677 ret = execv(path, discard_const(new_argv));
681 /* Should not happen */
685 talloc_free(new_argv);
687 ret = waitpid(pid, &status, 0);
690 fprintf(stderr, "waitpid() failed for %s - %s\n",
691 command, strerror(save_errno));
695 if (WIFEXITED(status)) {
696 ret = WEXITSTATUS(status);
700 if (WIFSIGNALED(status)) {
701 fprintf(stderr, "%s terminated with signal %d\n",
702 command, WTERMSIG(status));
713 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
714 int argc, const char **argv)
716 printf("%s\n", CTDB_VERSION_STRING);
720 static bool partially_online(TALLOC_CTX *mem_ctx,
721 struct ctdb_context *ctdb,
722 struct ctdb_node_and_flags *node)
724 struct ctdb_iface_list *iface_list;
728 if (node->flags != 0) {
732 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
733 node->pnn, TIMEOUT(), &iface_list);
739 for (i=0; i < iface_list->num; i++) {
740 if (iface_list->iface[i].link_state == 0) {
749 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
750 struct ctdb_context *ctdb,
751 struct ctdb_node_map *nodemap,
754 struct ctdb_node_and_flags *node;
757 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
761 "Disconnected", options.sep,
762 "Banned", options.sep,
763 "Disabled", options.sep,
764 "Unhealthy", options.sep,
765 "Stopped", options.sep,
766 "Inactive", options.sep,
767 "PartiallyOnline", options.sep,
768 "ThisNode", options.sep);
770 for (i=0; i<nodemap->num; i++) {
771 node = &nodemap->node[i];
772 if (node->flags & NODE_FLAGS_DELETED) {
776 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
778 node->pnn, options.sep,
779 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
781 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
782 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
783 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
785 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
786 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
787 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
788 partially_online(mem_ctx, ctdb, node), options.sep,
789 (node->pnn == mypnn)?'Y':'N', options.sep);
794 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
795 struct ctdb_node_map *nodemap, uint32_t mypnn)
797 struct ctdb_node_and_flags *node;
798 int num_deleted_nodes = 0;
801 for (i=0; i<nodemap->num; i++) {
802 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
807 if (num_deleted_nodes == 0) {
808 printf("Number of nodes:%d\n", nodemap->num);
810 printf("Number of nodes:%d (including %d deleted nodes)\n",
811 nodemap->num, num_deleted_nodes);
814 for (i=0; i<nodemap->num; i++) {
815 node = &nodemap->node[i];
816 if (node->flags & NODE_FLAGS_DELETED) {
820 printf("pnn:%u %-16s %s%s\n",
822 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
823 partially_online(mem_ctx, ctdb, node) ?
825 pretty_print_flags(mem_ctx, node->flags),
826 node->pnn == mypnn ? " (THIS NODE)" : "");
830 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
831 struct ctdb_node_map *nodemap, uint32_t mypnn,
832 struct ctdb_vnn_map *vnnmap, int recmode,
837 print_nodemap(mem_ctx, ctdb, nodemap, mypnn);
839 if (vnnmap->generation == INVALID_GENERATION) {
840 printf("Generation:INVALID\n");
842 printf("Generation:%u\n", vnnmap->generation);
844 printf("Size:%d\n", vnnmap->size);
845 for (i=0; i<vnnmap->size; i++) {
846 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
849 printf("Recovery mode:%s (%d)\n",
850 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
852 printf("Recovery master:%d\n", recmaster);
855 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
856 int argc, const char **argv)
858 struct ctdb_node_map *nodemap;
859 struct ctdb_vnn_map *vnnmap;
868 nodemap = get_nodemap(ctdb, false);
869 if (nodemap == NULL) {
873 if (options.machinereadable == 1) {
874 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
878 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
879 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
884 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
885 ctdb->cmd_pnn, TIMEOUT(), &recmode);
890 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
891 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
896 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
901 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
902 int argc, const char **argv)
904 struct ctdb_uptime *uptime;
905 int ret, tmp, days, hours, minutes, seconds;
907 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
908 ctdb->cmd_pnn, TIMEOUT(), &uptime);
913 printf("Current time of node %-4u : %s",
914 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
916 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
917 seconds = tmp % 60; tmp /= 60;
918 minutes = tmp % 60; tmp /= 60;
919 hours = tmp % 24; tmp /= 24;
922 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
923 days, hours, minutes, seconds,
924 ctime(&uptime->ctdbd_start_time.tv_sec));
926 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
927 seconds = tmp % 60; tmp /= 60;
928 minutes = tmp % 60; tmp /= 60;
929 hours = tmp % 24; tmp /= 24;
932 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
933 days, hours, minutes, seconds,
934 ctime(&uptime->last_recovery_finished.tv_sec));
936 printf("Duration of last recovery/failover: %lf seconds\n",
937 timeval_delta(&uptime->last_recovery_finished,
938 &uptime->last_recovery_started));
943 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
944 int argc, const char **argv)
947 int ret, num_clients;
949 tv = timeval_current();
950 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
951 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
956 printf("response from %u time=%.6f sec (%d clients)\n",
957 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
961 const char *runstate_to_string(enum ctdb_runstate runstate);
962 enum ctdb_runstate runstate_from_string(const char *runstate_str);
964 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
965 int argc, const char **argv)
967 enum ctdb_runstate runstate;
971 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
972 ctdb->cmd_pnn, TIMEOUT(), &runstate);
978 for (i=0; i<argc; i++) {
979 enum ctdb_runstate t;
982 t = ctdb_runstate_from_string(argv[i]);
983 if (t == CTDB_RUNSTATE_UNKNOWN) {
984 printf("Invalid run state (%s)\n", argv[i]);
995 printf("CTDB not in required run state (got %s)\n",
996 ctdb_runstate_to_string(runstate));
1000 printf("%s\n", ctdb_runstate_to_string(runstate));
1004 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1005 int argc, const char **argv)
1007 struct ctdb_var_list *tun_var_list;
1016 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1017 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1020 "Failed to get list of variables from node %u\n",
1026 for (i=0; i<tun_var_list->count; i++) {
1027 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1034 printf("No such tunable %s\n", argv[0]);
1038 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1039 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1044 printf("%-26s = %u\n", argv[0], value);
1048 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1049 int argc, const char **argv)
1051 struct ctdb_var_list *tun_var_list;
1052 struct ctdb_tunable tunable;
1060 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1061 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1064 "Failed to get list of variables from node %u\n",
1070 for (i=0; i<tun_var_list->count; i++) {
1071 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1078 printf("No such tunable %s\n", argv[0]);
1082 tunable.name = argv[0];
1083 tunable.value = strtoul(argv[1], NULL, 0);
1085 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1086 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1090 "Setting obsolete tunable variable '%s'\n",
1099 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1100 int argc, const char **argv)
1102 struct ctdb_var_list *tun_var_list;
1109 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1110 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1115 for (i=0; i<tun_var_list->count; i++) {
1116 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1125 } stats_fields[] = {
1126 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1127 STATISTICS_FIELD(num_clients),
1128 STATISTICS_FIELD(frozen),
1129 STATISTICS_FIELD(recovering),
1130 STATISTICS_FIELD(num_recoveries),
1131 STATISTICS_FIELD(client_packets_sent),
1132 STATISTICS_FIELD(client_packets_recv),
1133 STATISTICS_FIELD(node_packets_sent),
1134 STATISTICS_FIELD(node_packets_recv),
1135 STATISTICS_FIELD(keepalive_packets_sent),
1136 STATISTICS_FIELD(keepalive_packets_recv),
1137 STATISTICS_FIELD(node.req_call),
1138 STATISTICS_FIELD(node.reply_call),
1139 STATISTICS_FIELD(node.req_dmaster),
1140 STATISTICS_FIELD(node.reply_dmaster),
1141 STATISTICS_FIELD(node.reply_error),
1142 STATISTICS_FIELD(node.req_message),
1143 STATISTICS_FIELD(node.req_control),
1144 STATISTICS_FIELD(node.reply_control),
1145 STATISTICS_FIELD(client.req_call),
1146 STATISTICS_FIELD(client.req_message),
1147 STATISTICS_FIELD(client.req_control),
1148 STATISTICS_FIELD(timeouts.call),
1149 STATISTICS_FIELD(timeouts.control),
1150 STATISTICS_FIELD(timeouts.traverse),
1151 STATISTICS_FIELD(locks.num_calls),
1152 STATISTICS_FIELD(locks.num_current),
1153 STATISTICS_FIELD(locks.num_pending),
1154 STATISTICS_FIELD(locks.num_failed),
1155 STATISTICS_FIELD(total_calls),
1156 STATISTICS_FIELD(pending_calls),
1157 STATISTICS_FIELD(childwrite_calls),
1158 STATISTICS_FIELD(pending_childwrite_calls),
1159 STATISTICS_FIELD(memory_used),
1160 STATISTICS_FIELD(max_hop_count),
1161 STATISTICS_FIELD(total_ro_delegations),
1162 STATISTICS_FIELD(total_ro_revokes),
1165 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1167 static void print_statistics_machine(struct ctdb_statistics *s,
1173 printf("CTDB version%s", options.sep);
1174 printf("Current time of statistics%s", options.sep);
1175 printf("Statistics collected since%s", options.sep);
1176 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1177 printf("%s%s", stats_fields[i].name, options.sep);
1179 printf("num_reclock_ctdbd_latency%s", options.sep);
1180 printf("min_reclock_ctdbd_latency%s", options.sep);
1181 printf("avg_reclock_ctdbd_latency%s", options.sep);
1182 printf("max_reclock_ctdbd_latency%s", options.sep);
1184 printf("num_reclock_recd_latency%s", options.sep);
1185 printf("min_reclock_recd_latency%s", options.sep);
1186 printf("avg_reclock_recd_latency%s", options.sep);
1187 printf("max_reclock_recd_latency%s", options.sep);
1189 printf("num_call_latency%s", options.sep);
1190 printf("min_call_latency%s", options.sep);
1191 printf("avg_call_latency%s", options.sep);
1192 printf("max_call_latency%s", options.sep);
1194 printf("num_lockwait_latency%s", options.sep);
1195 printf("min_lockwait_latency%s", options.sep);
1196 printf("avg_lockwait_latency%s", options.sep);
1197 printf("max_lockwait_latency%s", options.sep);
1199 printf("num_childwrite_latency%s", options.sep);
1200 printf("min_childwrite_latency%s", options.sep);
1201 printf("avg_childwrite_latency%s", options.sep);
1202 printf("max_childwrite_latency%s", options.sep);
1206 printf("%u%s", CTDB_PROTOCOL, options.sep);
1207 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1208 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1209 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1211 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1214 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1215 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1216 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1217 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1219 printf("%u%s", s->reclock.recd.num, options.sep);
1220 printf("%.6f%s", s->reclock.recd.min, options.sep);
1221 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1222 printf("%.6f%s", s->reclock.recd.max, options.sep);
1224 printf("%d%s", s->call_latency.num, options.sep);
1225 printf("%.6f%s", s->call_latency.min, options.sep);
1226 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1227 printf("%.6f%s", s->call_latency.max, options.sep);
1229 printf("%d%s", s->childwrite_latency.num, options.sep);
1230 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1231 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1232 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1236 static void print_statistics(struct ctdb_statistics *s)
1238 int tmp, days, hours, minutes, seconds;
1240 const char *prefix = NULL;
1243 tmp = s->statistics_current_time.tv_sec -
1244 s->statistics_start_time.tv_sec;
1245 seconds = tmp % 60; tmp /= 60;
1246 minutes = tmp % 60; tmp /= 60;
1247 hours = tmp % 24; tmp /= 24;
1250 printf("CTDB version %u\n", CTDB_PROTOCOL);
1251 printf("Current time of statistics : %s",
1252 ctime(&s->statistics_current_time.tv_sec));
1253 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1254 days, hours, minutes, seconds,
1255 ctime(&s->statistics_start_time.tv_sec));
1257 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1258 if (strchr(stats_fields[i].name, '.') != NULL) {
1259 preflen = strcspn(stats_fields[i].name, ".") + 1;
1261 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1262 prefix = stats_fields[i].name;
1263 printf(" %*.*s\n", preflen-1, preflen-1,
1264 stats_fields[i].name);
1269 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1270 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1271 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1274 printf(" hop_count_buckets:");
1275 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1276 printf(" %d", s->hop_count_bucket[i]);
1279 printf(" lock_buckets:");
1280 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1281 printf(" %d", s->locks.buckets[i]);
1284 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1285 "locks_latency MIN/AVG/MAX",
1286 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1287 s->locks.latency.max, s->locks.latency.num);
1289 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1290 "reclock_ctdbd MIN/AVG/MAX",
1291 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1292 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1294 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1295 "reclock_recd MIN/AVG/MAX",
1296 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1297 s->reclock.recd.max, s->reclock.recd.num);
1299 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1300 "call_latency MIN/AVG/MAX",
1301 s->call_latency.min, LATENCY_AVG(s->call_latency),
1302 s->call_latency.max, s->call_latency.num);
1304 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1305 "childwrite_latency MIN/AVG/MAX",
1306 s->childwrite_latency.min,
1307 LATENCY_AVG(s->childwrite_latency),
1308 s->childwrite_latency.max, s->childwrite_latency.num);
1311 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1312 int argc, const char **argv)
1314 struct ctdb_statistics *stats;
1318 usage("statistics");
1321 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1322 ctdb->cmd_pnn, TIMEOUT(), &stats);
1327 if (options.machinereadable) {
1328 print_statistics_machine(stats, true);
1330 print_statistics(stats);
1336 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1337 struct ctdb_context *ctdb,
1338 int argc, const char **argv)
1343 usage("statisticsreset");
1346 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1347 ctdb->cmd_pnn, TIMEOUT());
1355 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1356 int argc, const char **argv)
1358 struct ctdb_statistics_list *slist;
1359 int ret, count = 0, i;
1360 bool show_header = true;
1367 count = atoi(argv[0]);
1370 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1371 ctdb->cmd_pnn, TIMEOUT(), &slist);
1376 for (i=0; i<slist->num; i++) {
1377 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1380 if (options.machinereadable == 1) {
1381 print_statistics_machine(&slist->stats[i],
1383 show_header = false;
1385 print_statistics(&slist->stats[i]);
1387 if (count > 0 && i == count) {
1395 static int ctdb_public_ip_cmp(const void *a, const void *b)
1397 const struct ctdb_public_ip *ip_a = a;
1398 const struct ctdb_public_ip *ip_b = b;
1400 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1403 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1404 struct ctdb_public_ip_list *ips,
1405 struct ctdb_public_ip_info **ipinfo,
1409 char *conf, *avail, *active;
1411 if (options.machinereadable == 1) {
1412 printf("%s%s%s%s%s", options.sep,
1413 "Public IP", options.sep,
1414 "Node", options.sep);
1415 if (options.verbose == 1) {
1416 printf("%s%s%s%s%s%s\n",
1417 "ActiveInterfaces", options.sep,
1418 "AvailableInterfaces", options.sep,
1419 "ConfiguredInterfaces", options.sep);
1425 printf("Public IPs on ALL nodes\n");
1427 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1431 for (i = 0; i < ips->num; i++) {
1433 if (options.machinereadable == 1) {
1434 printf("%s%s%s%d%s", options.sep,
1435 ctdb_sock_addr_to_string(
1436 mem_ctx, &ips->ip[i].addr),
1438 (int)ips->ip[i].pnn, options.sep);
1440 printf("%s", ctdb_sock_addr_to_string(
1441 mem_ctx, &ips->ip[i].addr));
1444 if (options.verbose == 0) {
1445 if (options.machinereadable == 1) {
1448 printf(" %d\n", (int)ips->ip[i].pnn);
1457 if (ipinfo[i] == NULL) {
1461 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1462 struct ctdb_iface *iface;
1464 iface = &ipinfo[i]->ifaces->iface[j];
1466 conf = talloc_strdup(mem_ctx, iface->name);
1468 conf = talloc_asprintf_append(
1469 conf, ",%s", iface->name);
1472 if (ipinfo[i]->active_idx == j) {
1473 active = iface->name;
1476 if (iface->link_state == 0) {
1480 if (avail == NULL) {
1481 avail = talloc_strdup(mem_ctx, iface->name);
1483 avail = talloc_asprintf_append(
1484 avail, ",%s", iface->name);
1490 if (options.machinereadable == 1) {
1491 printf("%s%s%s%s%s%s\n",
1492 active ? active : "", options.sep,
1493 avail ? avail : "", options.sep,
1494 conf ? conf : "", options.sep);
1496 printf(" node[%d] active[%s] available[%s]"
1497 " configured[%s]\n",
1498 (int)ips->ip[i].pnn, active ? active : "",
1499 avail ? avail : "", conf ? conf : "");
1504 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1505 size_t datalen, void *private_data)
1507 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1508 private_data, struct ctdb_public_ip_list);
1509 struct ctdb_public_ip *ip;
1511 ip = (struct ctdb_public_ip *)databuf;
1512 ips->ip[ips->num] = *ip;
1518 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1519 struct ctdb_public_ip_list **out)
1521 struct ctdb_node_map *nodemap;
1522 struct ctdb_public_ip_list *ips;
1523 struct db_hash_context *ipdb;
1525 int ret, count, i, j;
1527 nodemap = get_nodemap(ctdb, false);
1528 if (nodemap == NULL) {
1532 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1537 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1543 for (i=0; i<count; i++) {
1544 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1545 pnn_list[i], TIMEOUT(), &ips);
1550 for (j=0; j<ips->num; j++) {
1551 struct ctdb_public_ip ip;
1553 ip.pnn = ips->ip[j].pnn;
1554 ip.addr = ips->ip[j].addr;
1556 if (pnn_list[i] == ip.pnn) {
1557 /* Node claims IP is hosted on it, so
1558 * save that information
1560 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1562 (uint8_t *)&ip, sizeof(ip));
1567 /* Node thinks IP is hosted elsewhere,
1568 * so overwrite with CTDB_UNKNOWN_PNN
1569 * if there's no existing entry
1571 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1573 if (ret == ENOENT) {
1574 ip.pnn = CTDB_UNKNOWN_PNN;
1575 ret = db_hash_add(ipdb,
1576 (uint8_t *)&ip.addr,
1590 talloc_free(pnn_list);
1592 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1597 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1602 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1603 if (ips->ip == NULL) {
1607 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1612 if (count != ips->num) {
1626 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1627 int argc, const char **argv)
1629 struct ctdb_public_ip_list *ips;
1630 struct ctdb_public_ip_info **ipinfo;
1632 bool do_all = false;
1639 if (strcmp(argv[0], "all") == 0) {
1647 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1649 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1650 ctdb->cmd_pnn, TIMEOUT(), &ips);
1656 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1657 ctdb_public_ip_cmp);
1659 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1660 if (ipinfo == NULL) {
1664 for (i=0; i<ips->num; i++) {
1667 pnn = ips->ip[i].pnn;
1669 pnn = ctdb->cmd_pnn;
1671 if (pnn == CTDB_UNKNOWN_PNN) {
1675 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1677 TIMEOUT(), &ips->ip[i].addr,
1684 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1688 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1689 int argc, const char **argv)
1691 struct ctdb_public_ip_info *ipinfo;
1692 ctdb_sock_addr addr;
1699 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1700 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1704 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1705 ctdb->cmd_pnn, TIMEOUT(), &addr,
1709 printf("Node %u does not know about IP %s\n",
1710 ctdb->cmd_pnn, argv[0]);
1715 printf("Public IP[%s] info on node %u\n",
1716 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1719 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1720 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1721 ipinfo->ip.pnn, ipinfo->ifaces->num);
1723 for (i=0; i<ipinfo->ifaces->num; i++) {
1724 struct ctdb_iface *iface;
1726 iface = &ipinfo->ifaces->iface[i];
1727 iface->name[CTDB_IFACE_SIZE] = '\0';
1728 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1730 iface->link_state == 0 ? "down" : "up",
1732 (i == ipinfo->active_idx) ? " (active)" : "");
1738 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1739 int argc, const char **argv)
1741 struct ctdb_iface_list *ifaces;
1748 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1749 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1754 if (ifaces->num == 0) {
1755 printf("No interfaces configured on node %u\n",
1760 if (options.machinereadable) {
1761 printf("%s%s%s%s%s%s%s\n", options.sep,
1762 "Name", options.sep,
1763 "LinkStatus", options.sep,
1764 "References", options.sep);
1766 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1769 for (i=0; i<ifaces->num; i++) {
1770 if (options.machinereadable) {
1771 printf("%s%s%s%u%s%u%s\n", options.sep,
1772 ifaces->iface[i].name, options.sep,
1773 ifaces->iface[i].link_state, options.sep,
1774 ifaces->iface[i].references, options.sep);
1776 printf("name:%s link:%s references:%u\n",
1777 ifaces->iface[i].name,
1778 ifaces->iface[i].link_state ? "up" : "down",
1779 ifaces->iface[i].references);
1786 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1787 int argc, const char **argv)
1789 struct ctdb_iface_list *ifaces;
1790 struct ctdb_iface *iface;
1794 usage("setifacelink");
1797 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1798 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1802 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1803 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1806 "Failed to get interface information from node %u\n",
1812 for (i=0; i<ifaces->num; i++) {
1813 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1814 iface = &ifaces->iface[i];
1819 if (iface == NULL) {
1820 printf("Interface %s not configured on node %u\n",
1821 argv[0], ctdb->cmd_pnn);
1825 if (strcmp(argv[1], "up") == 0) {
1826 iface->link_state = 1;
1827 } else if (strcmp(argv[1], "down") == 0) {
1828 iface->link_state = 0;
1830 usage("setifacelink");
1834 iface->references = 0;
1836 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1837 ctdb->cmd_pnn, TIMEOUT(), iface);
1845 static int control_process_exists(TALLOC_CTX *mem_ctx,
1846 struct ctdb_context *ctdb,
1847 int argc, const char **argv)
1853 usage("process-exists");
1856 pid = atoi(argv[0]);
1857 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1858 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1864 printf("PID %u exists\n", pid);
1866 printf("PID %u does not exist\n", pid);
1871 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1872 int argc, const char **argv)
1874 struct ctdb_dbid_map *dbmap;
1881 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1882 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1887 if (options.machinereadable == 1) {
1888 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1891 "Name", options.sep,
1892 "Path", options.sep,
1893 "Persistent", options.sep,
1894 "Sticky", options.sep,
1895 "Unhealthy", options.sep,
1896 "Readonly", options.sep);
1898 printf("Number of databases:%d\n", dbmap->num);
1901 for (i=0; i<dbmap->num; i++) {
1910 db_id = dbmap->dbs[i].db_id;
1912 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1913 ctdb->cmd_pnn, TIMEOUT(), db_id,
1919 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1920 ctdb->cmd_pnn, TIMEOUT(), db_id,
1926 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1927 ctdb->cmd_pnn, TIMEOUT(), db_id,
1933 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1934 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1935 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1937 if (options.machinereadable == 1) {
1938 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s\n",
1943 !! (persistent), options.sep,
1944 !! (sticky), options.sep,
1945 !! (health), options.sep,
1946 !! (readonly), options.sep);
1948 printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
1950 persistent ? " PERSISTENT" : "",
1951 sticky ? " STICKY" : "",
1952 readonly ? " READONLY" : "",
1953 health ? " UNHEALTHY" : "");
1956 talloc_free(discard_const(name));
1957 talloc_free(discard_const(path));
1958 talloc_free(discard_const(health));
1964 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1965 int argc, const char **argv)
1968 const char *db_name, *db_path, *db_health;
1973 usage("getdbstatus");
1976 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
1980 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1981 ctdb->cmd_pnn, TIMEOUT(), db_id,
1987 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1988 ctdb->cmd_pnn, TIMEOUT(), db_id,
1994 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
1995 printf("PERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
1996 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
1997 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
1998 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"),
1999 (db_health ? db_health : "OK"));
2003 struct dump_record_state {
2007 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2009 static void dump_tdb_data(const char *name, TDB_DATA val)
2013 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2014 for (i=0; i<val.dsize; i++) {
2015 if (ISASCII(val.dptr[i])) {
2016 fprintf(stdout, "%c", val.dptr[i]);
2018 fprintf(stdout, "\\%02X", val.dptr[i]);
2021 fprintf(stdout, "\"\n");
2024 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2026 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2027 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2028 fprintf(stdout, "flags: 0x%08x", header->flags);
2029 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2030 fprintf(stdout, " MIGRATED_WITH_DATA");
2032 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2033 fprintf(stdout, " VACUUM_MIGRATED");
2035 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2036 fprintf(stdout, " AUTOMATIC");
2038 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2039 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2041 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2042 fprintf(stdout, " RO_HAVE_READONLY");
2044 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2045 fprintf(stdout, " RO_REVOKING_READONLY");
2047 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2048 fprintf(stdout, " RO_REVOKE_COMPLETE");
2050 fprintf(stdout, "\n");
2054 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2055 TDB_DATA key, TDB_DATA data, void *private_data)
2057 struct dump_record_state *state =
2058 (struct dump_record_state *)private_data;
2062 dump_tdb_data("key", key);
2063 dump_ltdb_header(header);
2064 dump_tdb_data("data", data);
2065 fprintf(stdout, "\n");
2070 struct traverse_state {
2071 TALLOC_CTX *mem_ctx;
2073 ctdb_rec_parser_func_t func;
2074 struct dump_record_state sub_state;
2077 static void traverse_handler(uint64_t srvid, TDB_DATA data, void *private_data)
2079 struct traverse_state *state = (struct traverse_state *)private_data;
2080 struct ctdb_rec_data *rec;
2081 struct ctdb_ltdb_header header;
2084 ret = ctdb_rec_data_pull(data.dptr, data.dsize, state->mem_ctx, &rec);
2089 if (rec->key.dsize == 0 && rec->data.dsize == 0) {
2091 /* end of traverse */
2096 ret = ctdb_ltdb_header_extract(&rec->data, &header);
2102 if (rec->data.dsize == 0) {
2107 ret = state->func(rec->reqid, &header, rec->key, rec->data,
2115 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2116 int argc, const char **argv)
2118 struct ctdb_db_context *db;
2119 const char *db_name;
2122 struct ctdb_traverse_start_ext traverse;
2123 struct traverse_state state;
2130 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2134 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2137 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2142 ZERO_STRUCT(traverse);
2144 traverse.db_id = db_id;
2146 traverse.srvid = next_srvid(ctdb);
2147 traverse.withemptyrecords = false;
2149 state.mem_ctx = mem_ctx;
2151 state.func = dump_record;
2152 state.sub_state.count = 0;
2154 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2156 traverse_handler, &state);
2161 ret = ctdb_ctrl_traverse_start_ext(mem_ctx, ctdb->ev, ctdb->client,
2162 ctdb->cmd_pnn, TIMEOUT(),
2168 ctdb_client_wait(ctdb->ev, &state.done);
2170 printf("Dumped %u records\n", state.sub_state.count);
2172 ret = ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2173 traverse.srvid, &state);
2181 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2182 int argc, const char **argv)
2184 struct ctdb_db_context *db;
2185 const char *db_name;
2188 struct dump_record_state state;
2195 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2199 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2202 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2207 ret = ctdb_db_traverse(db, true, true, dump_record, &state);
2209 printf("Dumped %u record(s)\n", state.count);
2214 static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2215 int argc, const char **argv)
2220 usage("getmonmode");
2223 ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
2224 ctdb->cmd_pnn, TIMEOUT(), &mode);
2230 (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
2234 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2235 struct ctdb_context *ctdb,
2236 int argc, const char **argv)
2242 usage("getcapabilities");
2245 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2246 ctdb->cmd_pnn, TIMEOUT(), &caps);
2251 if (options.machinereadable == 1) {
2252 printf("%s%s%s%s%s\n",
2254 "RECMASTER", options.sep,
2255 "LMASTER", options.sep);
2256 printf("%s%d%s%d%s\n", options.sep,
2257 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2258 !! (caps & CTDB_CAP_LMASTER), options.sep);
2260 printf("RECMASTER: %s\n",
2261 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2262 printf("LMASTER: %s\n",
2263 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2269 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2270 int argc, const char **argv)
2272 printf("%u\n", ctdb_client_pnn(ctdb->client));
2276 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2277 int argc, const char **argv)
2279 char *t, *lvs_helper = NULL;
2285 t = getenv("CTDB_LVS_HELPER");
2287 lvs_helper = talloc_strdup(mem_ctx, t);
2289 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2290 CTDB_HELPER_BINDIR);
2293 if (lvs_helper == NULL) {
2294 fprintf(stderr, "Unable to set LVS helper\n");
2298 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2301 static int control_disable_monitor(TALLOC_CTX *mem_ctx,
2302 struct ctdb_context *ctdb,
2303 int argc, const char **argv)
2308 usage("disablemonitor");
2311 ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2312 ctdb->cmd_pnn, TIMEOUT());
2320 static int control_enable_monitor(TALLOC_CTX *mem_ctx,
2321 struct ctdb_context *ctdb,
2322 int argc, const char **argv)
2327 usage("enablemonitor");
2330 ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2331 ctdb->cmd_pnn, TIMEOUT());
2339 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2340 int argc, const char **argv)
2350 found = debug_level_parse(argv[0], &log_level);
2353 "Invalid debug level '%s'. Valid levels are:\n",
2355 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2359 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2360 ctdb->cmd_pnn, TIMEOUT(), log_level);
2368 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2369 int argc, const char **argv)
2372 const char *log_str;
2379 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2380 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2385 log_str = debug_level_to_string(loglevel);
2386 printf("%s\n", log_str);
2391 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2392 int argc, const char **argv)
2394 const char *db_name;
2395 uint8_t db_flags = 0;
2398 if (argc < 1 || argc > 2) {
2404 if (strcmp(argv[1], "persistent") == 0) {
2405 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2406 } else if (strcmp(argv[1], "readonly") == 0) {
2407 db_flags = CTDB_DB_FLAGS_READONLY;
2408 } else if (strcmp(argv[1], "sticky") == 0) {
2409 db_flags = CTDB_DB_FLAGS_STICKY;
2415 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2424 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2425 int argc, const char **argv)
2427 const char *db_name;
2430 struct ctdb_node_map *nodemap;
2438 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2439 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2444 if (recmode == CTDB_RECOVERY_ACTIVE) {
2445 fprintf(stderr, "Database cannot be detached"
2446 " when recovery is active\n");
2450 nodemap = get_nodemap(ctdb, false);
2451 if (nodemap == NULL) {
2455 for (i=0; i<nodemap->num; i++) {
2458 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2461 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2464 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2465 fprintf(stderr, "Database cannot be detached on"
2466 " inactive (stopped or banned) node %u\n",
2467 nodemap->node[i].pnn);
2471 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2472 nodemap->node[i].pnn, TIMEOUT(),
2473 "AllowClientDBAttach", &value);
2476 "Unable to get tunable AllowClientDBAttach"
2477 " from node %u\n", nodemap->node[i].pnn);
2483 "Database access is still active on node %u."
2484 " Set AllowclientDBAttach=0 on all nodes.\n",
2485 nodemap->node[i].pnn);
2491 for (i=0; i<argc; i++) {
2492 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2497 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
2499 "Persistent database %s cannot be detached\n",
2504 ret = ctdb_detach(mem_ctx, ctdb->ev, ctdb->client,
2507 fprintf(stderr, "Database %s detach failed\n", db_name);
2515 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2516 int argc, const char **argv)
2518 const char *mem_str;
2522 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2523 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2528 n = write(1, mem_str, strlen(mem_str)+1);
2529 if (n < 0 || n != strlen(mem_str)+1) {
2530 fprintf(stderr, "Failed to write talloc summary\n");
2537 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2539 bool *done = (bool *)private_data;
2542 n = write(1, data.dptr, data.dsize);
2543 if (n < 0 || n != data.dsize) {
2544 fprintf(stderr, "Failed to write talloc summary\n");
2550 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2551 int argc, const char **argv)
2553 struct ctdb_srvid_message msg = { 0 };
2557 msg.pnn = ctdb->pnn;
2558 msg.srvid = next_srvid(ctdb);
2560 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2561 msg.srvid, dump_memory, &done);
2566 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2567 ctdb->cmd_pnn, &msg);
2572 ctdb_client_wait(ctdb->ev, &done);
2576 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2577 int argc, const char **argv)
2582 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2583 ctdb->cmd_pnn, TIMEOUT(), &pid);
2588 printf("%u\n", pid);
2592 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2593 const char *desc, uint32_t flag, bool set_flag)
2595 struct ctdb_node_map *nodemap;
2598 nodemap = get_nodemap(ctdb, false);
2599 if (nodemap == NULL) {
2603 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2604 if (set_flag == flag_is_set) {
2606 fprintf(stderr, "Node %u is already %s\n",
2607 ctdb->cmd_pnn, desc);
2609 fprintf(stderr, "Node %u is not %s\n",
2610 ctdb->cmd_pnn, desc);
2618 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2619 uint32_t flag, bool set_flag)
2621 struct ctdb_node_map *nodemap;
2625 nodemap = get_nodemap(ctdb, true);
2626 if (nodemap == NULL) {
2628 "Failed to get nodemap, trying again\n");
2633 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2634 if (flag_is_set == set_flag) {
2642 struct ipreallocate_state {
2647 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2650 struct ipreallocate_state *state =
2651 (struct ipreallocate_state *)private_data;
2653 if (data.dsize != sizeof(int)) {
2658 state->status = *(int *)data.dptr;
2662 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2664 struct ctdb_srvid_message msg = { 0 };
2665 struct ipreallocate_state state;
2668 msg.pnn = ctdb->pnn;
2669 msg.srvid = next_srvid(ctdb);
2672 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2674 ipreallocate_handler, &state);
2680 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2682 CTDB_BROADCAST_CONNECTED,
2688 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2694 if (state.status >= 0) {
2703 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2708 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2709 int argc, const char **argv)
2717 ret = check_flags(mem_ctx, ctdb, "disabled",
2718 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2723 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2724 ctdb->cmd_pnn, TIMEOUT(),
2725 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2728 "Failed to set DISABLED flag on node %u\n",
2733 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2734 return ipreallocate(mem_ctx, ctdb);
2737 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2738 int argc, const char **argv)
2746 ret = check_flags(mem_ctx, ctdb, "disabled",
2747 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2752 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2753 ctdb->cmd_pnn, TIMEOUT(),
2754 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2756 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2761 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2762 return ipreallocate(mem_ctx, ctdb);
2765 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2766 int argc, const char **argv)
2774 ret = check_flags(mem_ctx, ctdb, "stopped",
2775 NODE_FLAGS_STOPPED, true);
2780 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2781 ctdb->cmd_pnn, TIMEOUT());
2783 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2787 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2788 return ipreallocate(mem_ctx, ctdb);
2791 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2792 int argc, const char **argv)
2800 ret = check_flags(mem_ctx, ctdb, "stopped",
2801 NODE_FLAGS_STOPPED, false);
2806 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2807 ctdb->cmd_pnn, TIMEOUT());
2809 fprintf(stderr, "Failed to continue stopped node %u\n",
2814 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2815 return ipreallocate(mem_ctx, ctdb);
2818 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2819 int argc, const char **argv)
2821 struct ctdb_ban_state ban_state;
2828 ret = check_flags(mem_ctx, ctdb, "banned",
2829 NODE_FLAGS_BANNED, true);
2834 ban_state.pnn = ctdb->cmd_pnn;
2835 ban_state.time = strtoul(argv[0], NULL, 0);
2837 if (ban_state.time == 0) {
2838 fprintf(stderr, "Ban time cannot be zero\n");
2842 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2843 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2845 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2849 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2850 return ipreallocate(mem_ctx, ctdb);
2854 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2855 int argc, const char **argv)
2857 struct ctdb_ban_state ban_state;
2864 ret = check_flags(mem_ctx, ctdb, "banned",
2865 NODE_FLAGS_BANNED, false);
2870 ban_state.pnn = ctdb->cmd_pnn;
2873 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2874 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2876 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2880 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2881 return ipreallocate(mem_ctx, ctdb);
2885 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2886 int argc, const char **argv)
2894 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2895 ctdb->cmd_pnn, TIMEOUT());
2897 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2904 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2905 uint32_t *generation)
2909 struct ctdb_vnn_map *vnnmap;
2913 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2914 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2916 fprintf(stderr, "Failed to find recovery master\n");
2920 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2921 recmaster, TIMEOUT(), &recmode);
2923 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2928 if (recmode == CTDB_RECOVERY_ACTIVE) {
2933 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2934 recmaster, TIMEOUT(), &vnnmap);
2936 fprintf(stderr, "Failed to get generation from node %u\n",
2941 if (vnnmap->generation == INVALID_GENERATION) {
2942 talloc_free(vnnmap);
2947 *generation = vnnmap->generation;
2948 talloc_free(vnnmap);
2953 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2954 int argc, const char **argv)
2956 uint32_t generation, next_generation;
2963 ret = get_generation(mem_ctx, ctdb, &generation);
2968 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2969 ctdb->cmd_pnn, TIMEOUT(),
2970 CTDB_RECOVERY_ACTIVE);
2972 fprintf(stderr, "Failed to set recovery mode active\n");
2977 ret = get_generation(mem_ctx, ctdb, &next_generation);
2980 "Failed to confirm end of recovery\n");
2984 if (next_generation != generation) {
2994 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2995 int argc, const char **argv)
2998 usage("ipreallocate");
3001 return ipreallocate(mem_ctx, ctdb);
3004 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
3005 struct ctdb_context *ctdb,
3006 int argc, const char **argv)
3012 usage("isnotrecmaster");
3015 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
3016 ctdb->pnn, TIMEOUT(), &recmaster);
3018 fprintf(stderr, "Failed to get recmaster\n");
3022 if (recmaster != ctdb->pnn) {
3023 printf("this node is not the recmaster\n");
3027 printf("this node is the recmaster\n");
3031 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3032 int argc, const char **argv)
3034 struct ctdb_addr_info addr_info;
3041 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
3042 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3045 addr_info.iface = argv[1];
3047 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3048 ctdb->cmd_pnn, TIMEOUT(),
3051 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3059 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3060 int argc, const char **argv)
3062 ctdb_sock_addr src, dst;
3065 if (argc != 0 && argc != 2) {
3070 struct ctdb_connection *clist;
3074 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3080 for (i=0; i<count; i++) {
3081 ret = ctdb_sys_send_tcp(&clist[i].src,
3091 if (num_failed > 0) {
3092 fprintf(stderr, "Failed to send %d tickles\n",
3101 if (! parse_ip_port(argv[0], &src)) {
3102 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3106 if (! parse_ip_port(argv[1], &dst)) {
3107 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3111 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3113 fprintf(stderr, "Failed to send tickle ack\n");
3120 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3121 int argc, const char **argv)
3123 ctdb_sock_addr addr;
3124 struct ctdb_tickle_list *tickles;
3128 if (argc < 1 || argc > 2) {
3129 usage("gettickles");
3133 port = strtoul(argv[1], NULL, 10);
3136 if (! parse_ip(argv[0], NULL, port, &addr)) {
3137 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3141 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3142 ctdb->cmd_pnn, TIMEOUT(), &addr,
3145 fprintf(stderr, "Failed to get list of connections\n");
3149 if (options.machinereadable) {
3150 printf("%s%s%s%s%s%s%s%s%s\n",
3152 "Source IP", options.sep,
3153 "Port", options.sep,
3154 "Destiation IP", options.sep,
3155 "Port", options.sep);
3156 for (i=0; i<tickles->num; i++) {
3157 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3158 ctdb_sock_addr_to_string(
3159 mem_ctx, &tickles->conn[i].src),
3161 ntohs(tickles->conn[i].src.ip.sin_port),
3163 ctdb_sock_addr_to_string(
3164 mem_ctx, &tickles->conn[i].dst),
3166 ntohs(tickles->conn[i].dst.ip.sin_port),
3170 printf("Connections for IP: %s\n",
3171 ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
3172 printf("Num connections: %u\n", tickles->num);
3173 for (i=0; i<tickles->num; i++) {
3174 printf("SRC: %s:%u DST: %s:%u\n",
3175 ctdb_sock_addr_to_string(
3176 mem_ctx, &tickles->conn[i].src),
3177 ntohs(tickles->conn[i].src.ip.sin_port),
3178 ctdb_sock_addr_to_string(
3179 mem_ctx, &tickles->conn[i].dst),
3180 ntohs(tickles->conn[i].dst.ip.sin_port));
3184 talloc_free(tickles);
3188 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3189 struct ctdb_connection *conn);
3191 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3193 struct process_clist_state {
3194 struct ctdb_connection *clist;
3196 int num_failed, num_total;
3197 clist_reply_func reply_func;
3200 static void process_clist_done(struct tevent_req *subreq);
3202 static struct tevent_req *process_clist_send(
3203 TALLOC_CTX *mem_ctx,
3204 struct ctdb_context *ctdb,
3205 struct ctdb_connection *clist,
3207 clist_request_func request_func,
3208 clist_reply_func reply_func)
3210 struct tevent_req *req, *subreq;
3211 struct process_clist_state *state;
3212 struct ctdb_req_control request;
3215 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3220 state->clist = clist;
3221 state->count = count;
3222 state->reply_func = reply_func;
3224 for (i=0; i<count; i++) {
3225 request_func(&request, &clist[i]);
3226 subreq = ctdb_client_control_send(state, ctdb->ev,
3227 ctdb->client, ctdb->cmd_pnn,
3228 TIMEOUT(), &request);
3229 if (tevent_req_nomem(subreq, req)) {
3230 return tevent_req_post(req, ctdb->ev);
3232 tevent_req_set_callback(subreq, process_clist_done, req);
3238 static void process_clist_done(struct tevent_req *subreq)
3240 struct tevent_req *req = tevent_req_callback_data(
3241 subreq, struct tevent_req);
3242 struct process_clist_state *state = tevent_req_data(
3243 req, struct process_clist_state);
3244 struct ctdb_reply_control *reply;
3248 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3249 TALLOC_FREE(subreq);
3251 state->num_failed += 1;
3255 ret = state->reply_func(reply);
3257 state->num_failed += 1;
3262 state->num_total += 1;
3263 if (state->num_total == state->count) {
3264 tevent_req_done(req);
3268 static int process_clist_recv(struct tevent_req *req)
3270 struct process_clist_state *state = tevent_req_data(
3271 req, struct process_clist_state);
3273 return state->num_failed;
3276 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3277 int argc, const char **argv)
3279 struct ctdb_connection conn;
3282 if (argc != 0 && argc != 2) {
3287 struct ctdb_connection *clist;
3288 struct tevent_req *req;
3291 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3299 req = process_clist_send(mem_ctx, ctdb, clist, count,
3300 ctdb_req_control_tcp_add_delayed_update,
3301 ctdb_reply_control_tcp_add_delayed_update);
3307 tevent_req_poll(req, ctdb->ev);
3310 ret = process_clist_recv(req);
3312 fprintf(stderr, "Failed to add %d tickles\n", ret);
3319 if (! parse_ip_port(argv[0], &conn.src)) {
3320 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3323 if (! parse_ip_port(argv[1], &conn.dst)) {
3324 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3328 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3329 ctdb->client, ctdb->cmd_pnn,
3332 fprintf(stderr, "Failed to register connection\n");
3339 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3340 int argc, const char **argv)
3342 struct ctdb_connection conn;
3345 if (argc != 0 && argc != 2) {
3350 struct ctdb_connection *clist;
3351 struct tevent_req *req;
3354 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3362 req = process_clist_send(mem_ctx, ctdb, clist, count,
3363 ctdb_req_control_tcp_remove,
3364 ctdb_reply_control_tcp_remove);
3370 tevent_req_poll(req, ctdb->ev);
3373 ret = process_clist_recv(req);
3375 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3382 if (! parse_ip_port(argv[0], &conn.src)) {
3383 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3386 if (! parse_ip_port(argv[1], &conn.dst)) {
3387 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3391 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3392 ctdb->cmd_pnn, TIMEOUT(), &conn);
3394 fprintf(stderr, "Failed to unregister connection\n");
3401 static int control_check_srvids(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3402 int argc, const char **argv)
3409 usage("check_srvids");
3412 srvid = talloc_array(mem_ctx, uint64_t, argc);
3413 if (srvid == NULL) {
3414 fprintf(stderr, "Memory allocation error\n");
3418 for (i=0; i<argc; i++) {
3419 srvid[i] = strtoull(argv[i], NULL, 0);
3422 ret = ctdb_ctrl_check_srvids(mem_ctx, ctdb->ev, ctdb->client,
3423 ctdb->cmd_pnn, TIMEOUT(), srvid, argc,
3426 fprintf(stderr, "Failed to check srvids on node %u\n",
3431 for (i=0; i<argc; i++) {
3432 printf("SRVID 0x%" PRIx64 " %s\n", srvid[i],
3433 (result[i] ? "exists" : "does not exist"));
3439 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3440 int argc, const char **argv)
3442 struct ctdb_node_map *nodemap;
3449 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3450 if (nodemap == NULL) {
3454 for (i=0; i<nodemap->num; i++) {
3455 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3459 if (options.machinereadable) {
3460 printf("%s%u%s%s%s\n", options.sep,
3461 nodemap->node[i].pnn, options.sep,
3462 ctdb_sock_addr_to_string(
3463 mem_ctx, &nodemap->node[i].addr),
3467 ctdb_sock_addr_to_string(
3468 mem_ctx, &nodemap->node[i].addr));
3475 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3476 struct ctdb_node_map *nodemap2)
3480 if (nodemap1->num != nodemap2->num) {
3484 for (i=0; i<nodemap1->num; i++) {
3485 struct ctdb_node_and_flags *n1, *n2;
3487 n1 = &nodemap1->node[i];
3488 n2 = &nodemap2->node[i];
3490 if ((n1->pnn != n2->pnn) ||
3491 (n1->flags != n2->flags) ||
3492 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3500 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3501 struct ctdb_node_map *nm,
3502 struct ctdb_node_map *fnm,
3506 bool check_failed = false;
3510 for (i=0; i<nm->num; i++) {
3511 if (i >= fnm->num) {
3513 "Node %u (%s) missing from nodes file\n",
3515 ctdb_sock_addr_to_string(
3516 mem_ctx, &nm->node[i].addr));
3517 check_failed = true;
3520 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3521 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3522 /* Node remains deleted */
3526 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3527 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3528 /* Node not newly nor previously deleted */
3529 if (! ctdb_same_ip(&nm->node[i].addr,
3530 &fnm->node[i].addr)) {
3532 "Node %u has changed IP address"
3533 " (was %s, now %s)\n",
3535 ctdb_sock_addr_to_string(
3536 mem_ctx, &nm->node[i].addr),
3537 ctdb_sock_addr_to_string(
3538 mem_ctx, &fnm->node[i].addr));
3539 check_failed = true;
3541 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3543 "WARNING: Node %u is disconnected."
3544 " You MUST fix this node manually!\n",
3551 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3552 /* Node is being deleted */
3553 printf("Node %u is DELETED\n", nm->node[i].pnn);
3555 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3557 "ERROR: Node %u is still connected\n",
3559 check_failed = true;
3564 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3565 /* Node was previously deleted */
3566 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3573 "ERROR: Nodes will not be reloaded due to previous error\n");
3577 /* Leftover nodes in file are NEW */
3578 for (; i < fnm->num; i++) {
3579 printf("Node %u is NEW\n", fnm->node[i].pnn);
3586 struct disable_recoveries_state {
3594 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3597 struct disable_recoveries_state *state =
3598 (struct disable_recoveries_state *)private_data;
3601 if (data.dsize != sizeof(int)) {
3606 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3607 ret = *(int *)data.dptr;
3609 state->status = ret;
3613 for (i=0; i<state->node_count; i++) {
3614 if (state->pnn_list[i] == ret) {
3615 state->reply[i] = true;
3621 for (i=0; i<state->node_count; i++) {
3622 if (! state->reply[i]) {
3623 state->done = false;
3629 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3630 uint32_t timeout, uint32_t *pnn_list, int count)
3632 struct ctdb_disable_message disable = { 0 };
3633 struct disable_recoveries_state state;
3636 disable.pnn = ctdb->pnn;
3637 disable.srvid = next_srvid(ctdb);
3638 disable.timeout = timeout;
3640 state.pnn_list = pnn_list;
3641 state.node_count = count;
3644 state.reply = talloc_zero_array(mem_ctx, bool, count);
3645 if (state.reply == NULL) {
3649 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3651 disable_recoveries_handler,
3657 for (i=0; i<count; i++) {
3658 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3667 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3669 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3671 ret = (state.status >= 0 ? 0 : 1);
3675 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3676 disable.srvid, &state);
3680 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3681 int argc, const char **argv)
3683 struct ctdb_node_map *nodemap = NULL;
3684 struct ctdb_node_map *file_nodemap;
3685 struct ctdb_node_map *remote_nodemap;
3686 struct ctdb_req_control request;
3687 struct ctdb_reply_control **reply;
3693 nodemap = get_nodemap(ctdb, false);
3694 if (nodemap == NULL) {
3698 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3699 if (file_nodemap == NULL) {
3703 for (i=0; i<nodemap->num; i++) {
3704 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3708 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3709 nodemap->node[i].pnn, TIMEOUT(),
3713 "ERROR: Failed to get nodes file from node %u\n",
3714 nodemap->node[i].pnn);
3718 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3720 "ERROR: Nodes file on node %u differs"
3721 " from current node (%u)\n",
3722 nodemap->node[i].pnn, ctdb->pnn);
3727 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3733 fprintf(stderr, "No change in nodes file,"
3734 " skipping unnecessary reload\n");
3738 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3739 mem_ctx, &pnn_list);
3741 fprintf(stderr, "Memory allocation error\n");
3745 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3748 fprintf(stderr, "Failed to disable recoveries\n");
3752 ctdb_req_control_reload_nodes_file(&request);
3753 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3754 pnn_list, count, TIMEOUT(),
3755 &request, NULL, &reply);
3757 bool failed = false;
3759 for (i=0; i<count; i++) {
3760 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3763 "Node %u failed to reload nodes\n",
3770 "You MUST fix failed nodes manually!\n");
3774 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3776 fprintf(stderr, "Failed to enable recoveries\n");
3783 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3784 ctdb_sock_addr *addr, uint32_t pnn)
3786 struct ctdb_public_ip_list *pubip_list;
3787 struct ctdb_public_ip pubip;
3788 struct ctdb_node_map *nodemap;
3789 struct ctdb_req_control request;
3793 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3794 CTDB_BROADCAST_CONNECTED,
3795 2*options.timelimit);
3797 fprintf(stderr, "Failed to disable IP check\n");
3801 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3802 pnn, TIMEOUT(), &pubip_list);
3804 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3809 for (i=0; i<pubip_list->num; i++) {
3810 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3815 if (i == pubip_list->num) {
3816 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3817 pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
3821 nodemap = get_nodemap(ctdb, false);
3822 if (nodemap == NULL) {
3826 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3828 fprintf(stderr, "Memory allocation error\n");
3834 ctdb_req_control_release_ip(&request, &pubip);
3836 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3837 pnn_list, count, TIMEOUT(),
3838 &request, NULL, NULL);
3840 fprintf(stderr, "Failed to release IP on nodes\n");
3844 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3845 pnn, TIMEOUT(), &pubip);
3847 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3854 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3855 int argc, const char **argv)
3857 ctdb_sock_addr addr;
3859 int ret, retries = 0;
3865 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3866 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3870 pnn = strtoul(argv[1], NULL, 10);
3871 if (pnn == CTDB_UNKNOWN_PNN) {
3872 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3876 while (retries < 5) {
3877 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3887 fprintf(stderr, "Failed to move IP %s to node %u\n",
3895 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3900 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3901 CTDB_BROADCAST_CONNECTED, pnn);
3904 "Failed to ask recovery master to distribute IPs\n");
3911 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3912 int argc, const char **argv)
3914 ctdb_sock_addr addr;
3915 struct ctdb_public_ip_list *pubip_list;
3916 struct ctdb_addr_info addr_info;
3918 int ret, i, retries = 0;
3924 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3925 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3929 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3930 ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
3932 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3937 for (i=0; i<pubip_list->num; i++) {
3938 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3939 fprintf(stderr, "Node already knows about IP %s\n",
3940 ctdb_sock_addr_to_string(mem_ctx, &addr));
3945 addr_info.addr = addr;
3946 addr_info.mask = mask;
3947 addr_info.iface = argv[1];
3949 while (retries < 5) {
3950 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3951 ctdb->cmd_pnn, TIMEOUT(),
3962 fprintf(stderr, "Failed to add public IP to node %u."
3963 " Giving up\n", ctdb->cmd_pnn);
3967 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3975 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3976 int argc, const char **argv)
3978 ctdb_sock_addr addr;
3979 struct ctdb_public_ip_list *pubip_list;
3980 struct ctdb_addr_info addr_info;
3987 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3988 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3992 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3993 ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
3995 fprintf(stderr, "Failed to get Public IPs from node %u\n",
4000 for (i=0; i<pubip_list->num; i++) {
4001 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
4006 if (i == pubip_list->num) {
4007 fprintf(stderr, "Node does not know about IP address %s\n",
4008 ctdb_sock_addr_to_string(mem_ctx, &addr));
4012 addr_info.addr = addr;
4014 addr_info.iface = NULL;
4016 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4017 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
4019 fprintf(stderr, "Failed to delete public IP from node %u\n",
4027 static int control_eventscript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4028 int argc, const char **argv)
4033 usage("eventscript");
4036 if (strcmp(argv[0], "monitor") != 0) {
4037 fprintf(stderr, "Only monitor event can be run\n");
4041 ret = ctdb_ctrl_run_eventscripts(mem_ctx, ctdb->ev, ctdb->client,
4042 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4044 fprintf(stderr, "Failed to run monitor event on node %u\n",
4052 #define DB_VERSION 3
4053 #define MAX_DB_NAME 64
4054 #define MAX_REC_BUFFER_SIZE (100*1000)
4057 unsigned long version;
4059 unsigned long flags;
4062 char name[MAX_DB_NAME];
4065 struct backup_state {
4066 TALLOC_CTX *mem_ctx;
4067 struct ctdb_rec_buffer *recbuf;
4070 unsigned int nbuf, nrec;
4073 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4074 TDB_DATA key, TDB_DATA data, void *private_data)
4076 struct backup_state *state = (struct backup_state *)private_data;
4080 if (state->recbuf == NULL) {
4081 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4083 if (state->recbuf == NULL) {
4088 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4094 len = ctdb_rec_buffer_len(state->recbuf);
4095 if (len < MAX_REC_BUFFER_SIZE) {
4099 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4101 fprintf(stderr, "Failed to write records to backup file\n");
4106 state->nrec += state->recbuf->count;
4107 TALLOC_FREE(state->recbuf);
4112 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4113 int argc, const char **argv)
4115 const char *db_name;
4116 struct ctdb_db_context *db;
4119 struct backup_state state;
4120 struct db_header db_hdr;
4127 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4131 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4134 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4138 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4141 fprintf(stderr, "Failed to open file %s for writing\n",
4146 /* Write empty header first */
4147 ZERO_STRUCT(db_hdr);
4148 ret = write(fd, &db_hdr, sizeof(struct db_header));
4152 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4156 state.mem_ctx = mem_ctx;
4157 state.recbuf = NULL;
4162 ret = ctdb_db_traverse(db, true, false, backup_handler, &state);
4164 fprintf(stderr, "Failed to collect records from DB %s\n",
4170 if (state.recbuf != NULL) {
4171 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4174 "Failed to write records to backup file\n");
4180 state.nrec += state.recbuf->count;
4181 TALLOC_FREE(state.recbuf);
4184 db_hdr.version = DB_VERSION;
4185 db_hdr.timestamp = time(NULL);
4186 db_hdr.flags = db_flags;
4187 db_hdr.nbuf = state.nbuf;
4188 db_hdr.nrec = state.nrec;
4189 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4191 lseek(fd, 0, SEEK_SET);
4192 ret = write(fd, &db_hdr, sizeof(struct db_header));
4196 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4201 printf("Database backed up to %s\n", argv[1]);
4205 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4206 int argc, const char **argv)
4208 const char *db_name = NULL;
4209 struct ctdb_db_context *db;
4210 struct db_header db_hdr;
4211 struct ctdb_node_map *nodemap;
4212 struct ctdb_req_control request;
4213 struct ctdb_reply_control **reply;
4214 struct ctdb_transdb wipedb;
4215 struct ctdb_pulldb_ext pulldb;
4216 struct ctdb_rec_buffer *recbuf;
4217 uint32_t generation;
4223 if (argc < 1 || argc > 2) {
4227 fd = open(argv[0], O_RDONLY, 0600);
4230 fprintf(stderr, "Failed to open file %s for reading\n",
4239 ret = read(fd, &db_hdr, sizeof(struct db_header));
4243 fprintf(stderr, "Failed to read db header from file %s\n",
4247 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4249 if (db_hdr.version != DB_VERSION) {
4251 "Wrong version of backup file, expected %u, got %lu\n",
4252 DB_VERSION, db_hdr.version);
4257 if (db_name == NULL) {
4258 db_name = db_hdr.name;
4261 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4262 localtime(&db_hdr.timestamp));
4263 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4265 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4268 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4273 nodemap = get_nodemap(ctdb, false);
4274 if (nodemap == NULL) {
4275 fprintf(stderr, "Failed to get nodemap\n");
4280 ret = get_generation(mem_ctx, ctdb, &generation);
4282 fprintf(stderr, "Failed to get current generation\n");
4287 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4294 wipedb.db_id = ctdb_db_id(db);
4295 wipedb.tid = generation;
4297 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4298 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4299 ctdb->client, pnn_list, count,
4300 TIMEOUT(), &request, NULL, NULL);
4306 ctdb_req_control_db_transaction_start(&request, &wipedb);
4307 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4308 pnn_list, count, TIMEOUT(),
4309 &request, NULL, NULL);
4314 ctdb_req_control_wipe_database(&request, &wipedb);
4315 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4316 pnn_list, count, TIMEOUT(),
4317 &request, NULL, NULL);
4322 pulldb.db_id = ctdb_db_id(db);
4324 pulldb.srvid = SRVID_CTDB_PUSHDB;
4326 ctdb_req_control_db_push_start(&request, &pulldb);
4327 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4328 pnn_list, count, TIMEOUT(),
4329 &request, NULL, NULL);
4334 for (i=0; i<db_hdr.nbuf; i++) {
4335 struct ctdb_req_message message;
4338 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4343 data.dsize = ctdb_rec_buffer_len(recbuf);
4344 data.dptr = talloc_size(mem_ctx, data.dsize);
4345 if (data.dptr == NULL) {
4349 ctdb_rec_buffer_push(recbuf, data.dptr);
4351 message.srvid = pulldb.srvid;
4352 message.data.data = data;
4354 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4362 talloc_free(recbuf);
4363 talloc_free(data.dptr);
4366 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4367 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4368 pnn_list, count, TIMEOUT(),
4369 &request, NULL, &reply);
4374 for (i=0; i<count; i++) {
4375 uint32_t num_records;
4377 ret = ctdb_reply_control_db_push_confirm(reply[i],
4380 fprintf(stderr, "Invalid response from node %u\n",
4385 if (num_records != db_hdr.nrec) {
4386 fprintf(stderr, "Node %u received %u of %lu records\n",
4387 pnn_list[i], num_records, db_hdr.nrec);
4392 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4393 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4394 pnn_list, count, TIMEOUT(),
4395 &request, NULL, NULL);
4400 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4401 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4402 pnn_list, count, TIMEOUT(),
4403 &request, NULL, NULL);
4408 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4409 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4410 ctdb->client, pnn_list, count,
4411 TIMEOUT(), &request, NULL, NULL);
4416 printf("Database %s restored\n", db_name);
4422 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4423 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4427 struct dumpdbbackup_state {
4428 ctdb_rec_parser_func_t parser;
4429 struct dump_record_state sub_state;
4432 static int dumpdbbackup_handler(uint32_t reqid,
4433 struct ctdb_ltdb_header *header,
4434 TDB_DATA key, TDB_DATA data,
4437 struct dumpdbbackup_state *state =
4438 (struct dumpdbbackup_state *)private_data;
4439 struct ctdb_ltdb_header hdr;
4442 ret = ctdb_ltdb_header_extract(&data, &hdr);
4447 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4450 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4451 int argc, const char **argv)
4453 struct db_header db_hdr;
4455 struct dumpdbbackup_state state;
4459 usage("dumpbackup");
4462 fd = open(argv[0], O_RDONLY, 0600);
4465 fprintf(stderr, "Failed to open file %s for reading\n",
4470 ret = read(fd, &db_hdr, sizeof(struct db_header));
4474 fprintf(stderr, "Failed to read db header from file %s\n",
4478 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4480 if (db_hdr.version != DB_VERSION) {
4482 "Wrong version of backup file, expected %u, got %lu\n",
4483 DB_VERSION, db_hdr.version);
4488 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4489 localtime(&db_hdr.timestamp));
4490 printf("Dumping database %s from backup @ %s\n",
4491 db_hdr.name, timebuf);
4493 state.parser = dump_record;
4494 state.sub_state.count = 0;
4496 for (i=0; i<db_hdr.nbuf; i++) {
4497 struct ctdb_rec_buffer *recbuf;
4499 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4501 fprintf(stderr, "Failed to read records\n");
4506 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4509 fprintf(stderr, "Failed to dump records\n");
4516 printf("Dumped %u record(s)\n", state.sub_state.count);
4520 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4521 int argc, const char **argv)
4523 const char *db_name;
4524 struct ctdb_db_context *db;
4527 struct ctdb_node_map *nodemap;
4528 struct ctdb_req_control request;
4529 struct ctdb_transdb wipedb;
4530 uint32_t generation;
4538 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4542 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4545 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4549 nodemap = get_nodemap(ctdb, false);
4550 if (nodemap == NULL) {
4551 fprintf(stderr, "Failed to get nodemap\n");
4555 ret = get_generation(mem_ctx, ctdb, &generation);
4557 fprintf(stderr, "Failed to get current generation\n");
4561 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4567 ctdb_req_control_db_freeze(&request, db_id);
4568 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4569 ctdb->client, pnn_list, count,
4570 TIMEOUT(), &request, NULL, NULL);
4575 wipedb.db_id = db_id;
4576 wipedb.tid = generation;
4578 ctdb_req_control_db_transaction_start(&request, &wipedb);
4579 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4580 pnn_list, count, TIMEOUT(),
4581 &request, NULL, NULL);
4586 ctdb_req_control_wipe_database(&request, &wipedb);
4587 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4588 pnn_list, count, TIMEOUT(),
4589 &request, NULL, NULL);
4594 ctdb_req_control_db_set_healthy(&request, db_id);
4595 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4596 pnn_list, count, TIMEOUT(),
4597 &request, NULL, NULL);
4602 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4603 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4604 pnn_list, count, TIMEOUT(),
4605 &request, NULL, NULL);
4610 ctdb_req_control_db_thaw(&request, db_id);
4611 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4612 ctdb->client, pnn_list, count,
4613 TIMEOUT(), &request, NULL, NULL);
4618 printf("Database %s wiped\n", db_name);
4623 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4624 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4628 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4629 int argc, const char **argv)
4634 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4635 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4640 printf("%u\n", recmaster);
4644 static void print_scriptstatus_one(struct ctdb_script_list *slist,
4645 const char *event_str)
4650 if (slist == NULL) {
4651 if (! options.machinereadable) {
4652 printf("%s cycle never run\n", event_str);
4657 for (i=0; i<slist->num_scripts; i++) {
4658 if (slist->script[i].status != -ENOEXEC) {
4663 if (! options.machinereadable) {
4664 printf("%d scripts were executed last %s cycle\n",
4665 num_run, event_str);
4668 for (i=0; i<slist->num_scripts; i++) {
4669 const char *status = NULL;
4671 switch (slist->script[i].status) {
4673 status = "TIMEDOUT";
4676 status = "DISABLED";
4682 if (slist->script[i].status > 0) {
4688 if (options.machinereadable) {
4689 printf("%s%s%s%s%s%i%s%s%s%lu.%06lu%s%lu.%06lu%s%s%s\n",
4691 event_str, options.sep,
4692 slist->script[i].name, options.sep,
4693 slist->script[i].status, options.sep,
4694 status, options.sep,
4695 (unsigned long)slist->script[i].start.tv_sec,
4696 slist->script[i].start.tv_usec, options.sep,
4697 (unsigned long)slist->script[i].finished.tv_sec,
4698 slist->script[i].finished.tv_usec, options.sep,
4699 slist->script[i].output, options.sep);
4704 printf("%-20s Status:%s ",
4705 slist->script[i].name, status);
4707 /* Some other error, eg from stat. */
4708 printf("%-20s Status:CANNOT RUN (%s)",
4709 slist->script[i].name,
4710 strerror(-slist->script[i].status));
4713 if (slist->script[i].status >= 0) {
4714 printf("Duration:%.3lf ",
4715 timeval_delta(&slist->script[i].finished,
4716 &slist->script[i].start));
4718 if (slist->script[i].status != -ENOEXEC) {
4719 printf("%s", ctime(&slist->script[i].start.tv_sec));
4720 if (slist->script[i].status != 0) {
4721 printf(" OUTPUT:%s\n",
4722 slist->script[i].output);
4730 static void print_scriptstatus(struct ctdb_script_list **slist,
4731 int count, const char **event_str)
4735 if (options.machinereadable) {
4736 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
4738 "Type", options.sep,
4739 "Name", options.sep,
4740 "Code", options.sep,
4741 "Status", options.sep,
4742 "Start", options.sep,
4744 "Error Output", options.sep);
4747 for (i=0; i<count; i++) {
4748 print_scriptstatus_one(slist[i], event_str[i]);
4752 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4753 int argc, const char **argv)
4755 struct ctdb_script_list **slist;
4756 const char *event_str;
4757 enum ctdb_event event;
4758 const char *all_events[] = {
4759 "init", "setup", "startup", "monitor",
4760 "takeip", "releaseip", "updateip", "ipreallocated" };
4763 int count, start, end, num;
4766 usage("scriptstatus");
4770 event_str = "monitor";
4772 event_str = argv[0];
4778 for (i=0; i<ARRAY_SIZE(all_events); i++) {
4779 if (strcmp(event_str, all_events[i]) == 0) {
4788 if (strcmp(event_str, "all") == 0) {
4790 count = ARRAY_SIZE(all_events);
4796 fprintf(stderr, "Unknown event name %s\n", argv[0]);
4797 usage("scriptstatus");
4800 slist = talloc_array(mem_ctx, struct ctdb_script_list *, count);
4801 if (slist == NULL) {
4802 fprintf(stderr, "Memory allocation error\n");
4807 for (i=start; i<end; i++) {
4808 event = ctdb_event_from_string(all_events[i]);
4810 ret = ctdb_ctrl_get_event_script_status(mem_ctx, ctdb->ev,
4817 "failed to get script status for %s event\n",
4822 if (slist[num] == NULL) {
4827 /* The ETIME status is ignored for certain events.
4828 * In that case the status is 0, but endtime is not set.
4830 for (j=0; j<slist[num]->num_scripts; j++) {
4831 if (slist[num]->script[j].status == 0 &&
4832 timeval_is_zero(&slist[num]->script[j].finished)) {
4833 slist[num]->script[j].status = -ETIME;
4840 print_scriptstatus(slist, count, &all_events[start]);
4844 static int control_enablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4845 int argc, const char **argv)
4850 usage("enablescript");
4853 ret = ctdb_ctrl_enable_script(mem_ctx, ctdb->ev, ctdb->client,
4854 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4856 fprintf(stderr, "Failed to enable script %s\n", argv[0]);
4863 static int control_disablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4864 int argc, const char **argv)
4869 usage("disablescript");
4872 ret = ctdb_ctrl_disable_script(mem_ctx, ctdb->ev, ctdb->client,
4873 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4875 fprintf(stderr, "Failed to disable script %s\n", argv[0]);
4882 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4883 int argc, const char **argv)
4885 char *t, *natgw_helper = NULL;
4891 t = getenv("CTDB_NATGW_HELPER");
4893 natgw_helper = talloc_strdup(mem_ctx, t);
4895 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4896 CTDB_HELPER_BINDIR);
4899 if (natgw_helper == NULL) {
4900 fprintf(stderr, "Unable to set NAT gateway helper\n");
4904 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4908 static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4909 int argc, const char **argv)
4911 char *t, *natgw_helper = NULL;
4912 const char *cmd_argv[] = { "natgwlist", NULL };
4918 t = getenv("CTDB_NATGW_HELPER");
4920 natgw_helper = talloc_strdup(mem_ctx, t);
4922 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4923 CTDB_HELPER_BINDIR);
4926 if (natgw_helper == NULL) {
4927 fprintf(stderr, "Unable to set NAT gateway helper\n");
4931 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4936 * Find the PNN of the current node
4937 * discover the pnn by loading the nodes file and try to bind
4938 * to all addresses one at a time until the ip address is found.
4940 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4942 struct ctdb_node_map *nodemap;
4945 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4946 if (nodemap == NULL) {
4950 for (i=0; i<nodemap->num; i++) {
4951 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4954 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4956 *pnn = nodemap->node[i].pnn;
4958 talloc_free(nodemap);
4963 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4964 talloc_free(nodemap);
4968 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4969 int argc, const char **argv)
4971 const char *reclock;
4975 usage("getreclock");
4978 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4979 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4984 if (reclock != NULL) {
4985 printf("%s\n", reclock);
4991 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4992 struct ctdb_context *ctdb,
4993 int argc, const char **argv)
4995 uint32_t lmasterrole = 0;
4999 usage("setlmasterrole");
5002 if (strcmp(argv[0], "on") == 0) {
5004 } else if (strcmp(argv[0], "off") == 0) {
5007 usage("setlmasterrole");
5010 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
5011 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
5019 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
5020 struct ctdb_context *ctdb,
5021 int argc, const char **argv)
5023 uint32_t recmasterrole = 0;
5027 usage("setrecmasterrole");
5030 if (strcmp(argv[0], "on") == 0) {
5032 } else if (strcmp(argv[0], "off") == 0) {
5035 usage("setrecmasterrole");
5038 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
5039 ctdb->cmd_pnn, TIMEOUT(),
5048 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
5049 struct ctdb_context *ctdb,
5050 int argc, const char **argv)
5057 usage("setdbreadonly");
5060 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
5064 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5065 fprintf(stderr, "Cannot set READONLY on persistent DB\n");
5069 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
5070 ctdb->cmd_pnn, TIMEOUT(), db_id);
5078 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5079 int argc, const char **argv)
5086 usage("setdbsticky");
5089 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
5093 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5094 fprintf(stderr, "Cannot set STICKY on persistent DB\n");
5098 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
5099 ctdb->cmd_pnn, TIMEOUT(), db_id);
5107 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5108 int argc, const char **argv)
5110 const char *db_name;
5111 struct ctdb_db_context *db;
5112 struct ctdb_transaction_handle *h;
5117 if (argc < 2 || argc > 3) {
5121 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5125 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5126 fprintf(stderr, "DB %s is not a persistent database\n",
5131 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5134 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5138 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5140 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5144 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5145 TIMEOUT(), db, true, &h);
5147 fprintf(stderr, "Failed to start transaction on db %s\n",
5152 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
5154 fprintf(stderr, "Failed to read record for key %s\n",
5156 ctdb_transaction_cancel(h);
5160 printf("%.*s\n", (int)data.dsize, data.dptr);
5162 ctdb_transaction_cancel(h);
5166 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5167 int argc, const char **argv)
5169 const char *db_name;
5170 struct ctdb_db_context *db;
5171 struct ctdb_transaction_handle *h;
5180 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5184 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5185 fprintf(stderr, "DB %s is not a persistent database\n",
5190 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5193 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5197 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5199 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5203 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5205 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5209 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5210 TIMEOUT(), db, false, &h);
5212 fprintf(stderr, "Failed to start transaction on db %s\n",
5217 ret = ctdb_transaction_store_record(h, key, data);
5219 fprintf(stderr, "Failed to store record for key %s\n",
5221 ctdb_transaction_cancel(h);
5225 ret = ctdb_transaction_commit(h);
5227 fprintf(stderr, "Failed to commit transaction on db %s\n",
5229 ctdb_transaction_cancel(h);
5236 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5237 int argc, const char **argv)
5239 const char *db_name;
5240 struct ctdb_db_context *db;
5241 struct ctdb_transaction_handle *h;
5250 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5254 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5255 fprintf(stderr, "DB %s is not a persistent database\n",
5260 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5263 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5267 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5269 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5273 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5274 TIMEOUT(), db, false, &h);
5276 fprintf(stderr, "Failed to start transaction on db %s\n",
5281 ret = ctdb_transaction_delete_record(h, key);
5283 fprintf(stderr, "Failed to delete record for key %s\n",
5285 ctdb_transaction_cancel(h);
5289 ret = ctdb_transaction_commit(h);
5291 fprintf(stderr, "Failed to commit transaction on db %s\n",
5293 ctdb_transaction_cancel(h);
5300 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5308 /* Skip whitespace */
5309 n = strspn(*ptr, " \t");
5313 /* Quoted ASCII string - no wide characters! */
5315 n = strcspn(t, "\"");
5318 ret = str_to_data(t, n, mem_ctx, data);
5325 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5329 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5336 #define MAX_LINE_SIZE 1024
5338 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5339 TDB_DATA *key, TDB_DATA *value)
5341 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5345 ptr = fgets(line, MAX_LINE_SIZE, file);
5351 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5352 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5353 /* Line Ignored but not EOF */
5359 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5361 /* Line Ignored but not EOF */
5362 talloc_free(key->dptr);
5370 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5371 int argc, const char **argv)
5373 const char *db_name;
5374 struct ctdb_db_context *db;
5375 struct ctdb_transaction_handle *h;
5378 TDB_DATA key, value;
5381 if (argc < 1 || argc > 2) {
5385 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5389 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5390 fprintf(stderr, "DB %s is not a persistent database\n",
5396 file = fopen(argv[1], "r");
5398 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5405 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5408 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5412 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5413 TIMEOUT(), db, false, &h);
5415 fprintf(stderr, "Failed to start transaction on db %s\n",
5420 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5421 if (key.dsize != 0) {
5422 ret = ctdb_transaction_store_record(h, key, value);
5424 fprintf(stderr, "Failed to store record\n");
5425 ctdb_transaction_cancel(h);
5428 talloc_free(key.dptr);
5429 talloc_free(value.dptr);
5433 ret = ctdb_transaction_commit(h);
5435 fprintf(stderr, "Failed to commit transaction on db %s\n",
5437 ctdb_transaction_cancel(h);
5441 if (file != stdin) {
5447 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5448 int argc, const char **argv)
5450 struct tdb_context *tdb;
5452 struct ctdb_ltdb_header header;
5455 if (argc < 2 || argc > 3) {
5459 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5461 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5465 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5467 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5472 data = tdb_fetch(tdb, key);
5473 if (data.dptr == NULL) {
5474 fprintf(stderr, "No record for key %s\n", argv[1]);
5479 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5480 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5491 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5493 fprintf(stderr, "Failed to open output file %s\n",
5498 nwritten = sys_write(fd, data.dptr, data.dsize);
5499 if (nwritten != data.dsize) {
5500 fprintf(stderr, "Failed to write record to file\n");
5509 ret = ctdb_ltdb_header_extract(&data, &header);
5511 fprintf(stderr, "Failed to parse header from data\n");
5515 dump_ltdb_header(&header);
5516 dump_tdb_data("data", data);
5521 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5522 int argc, const char **argv)
5524 struct tdb_context *tdb;
5525 TDB_DATA key, data[2], value;
5526 struct ctdb_ltdb_header header;
5527 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5530 if (argc < 3 || argc > 5) {
5534 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5536 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5540 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5542 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5547 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5549 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5554 ZERO_STRUCT(header);
5557 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5560 header.dmaster = (uint32_t)atol(argv[4]);
5563 header.flags = (uint32_t)atol(argv[5]);
5566 ctdb_ltdb_header_push(&header, header_buf);
5568 data[0].dsize = ctdb_ltdb_header_len(&header);
5569 data[0].dptr = header_buf;
5571 data[1].dsize = value.dsize;
5572 data[1].dptr = value.dptr;
5574 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5576 fprintf(stderr, "Failed to write record %s to file %s\n",
5585 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5586 int argc, const char **argv)
5588 const char *db_name;
5589 struct ctdb_db_context *db;
5590 struct ctdb_record_handle *h;
5593 bool readonly = false;
5596 if (argc < 2 || argc > 3) {
5601 if (strcmp(argv[2], "readonly") == 0) {
5608 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5612 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5613 fprintf(stderr, "DB %s is not a volatile database\n",
5618 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5621 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5625 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5627 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5631 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5632 db, key, readonly, &h, NULL, &data);
5634 fprintf(stderr, "Failed to read record for key %s\n",
5637 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5638 (int)data.dsize, data.dptr);
5645 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5646 int argc, const char **argv)
5648 const char *db_name;
5649 struct ctdb_db_context *db;
5650 struct ctdb_record_handle *h;
5659 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5663 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5664 fprintf(stderr, "DB %s is not a volatile database\n",
5669 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5672 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5676 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5678 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5682 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5684 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5688 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5689 db, key, false, &h, NULL, NULL);
5691 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5695 ret = ctdb_store_record(h, data);
5697 fprintf(stderr, "Failed to store record for key %s\n",
5705 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5706 int argc, const char **argv)
5708 const char *db_name;
5709 struct ctdb_db_context *db;
5710 struct ctdb_record_handle *h;
5719 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5723 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5724 fprintf(stderr, "DB %s is not a volatile database\n",
5729 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5732 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5736 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5738 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5742 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5743 db, key, false, &h, NULL, &data);
5745 fprintf(stderr, "Failed to fetch record for key %s\n",
5750 ret = ctdb_delete_record(h);
5752 fprintf(stderr, "Failed to delete record for key %s\n",
5760 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5761 int argc, const char **argv)
5763 struct sockaddr_in sin;
5769 usage("chktcpport");
5772 port = atoi(argv[0]);
5774 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5776 fprintf(stderr, "Failed to open local socket\n");
5780 v = fcntl(s, F_GETFL, 0);
5781 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5782 fprintf(stderr, "Unable to set socket non-blocking\n");
5787 bzero(&sin, sizeof(sin));
5788 sin.sin_family = AF_INET;
5789 sin.sin_port = htons(port);
5790 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5793 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5800 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5801 int argc, const char **argv)
5804 const char *db_name;
5809 usage("getdbseqnum");
5812 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5816 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5817 ctdb->cmd_pnn, TIMEOUT(), db_id,
5820 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5825 printf("0x%"PRIx64"\n", seqnum);
5829 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5830 int argc, const char **argv)
5832 const char *nodestring = NULL;
5833 struct ctdb_node_map *nodemap;
5837 usage("nodestatus");
5841 nodestring = argv[0];
5844 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5848 nodemap = get_nodemap(ctdb, false);
5849 if (nodemap == NULL) {
5853 if (options.machinereadable) {
5854 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5856 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5860 for (i=0; i<nodemap->num; i++) {
5861 ret |= nodemap->node[i].flags;
5870 } db_stats_fields[] = {
5871 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5872 DBSTATISTICS_FIELD(db_ro_delegations),
5873 DBSTATISTICS_FIELD(db_ro_revokes),
5874 DBSTATISTICS_FIELD(locks.num_calls),
5875 DBSTATISTICS_FIELD(locks.num_current),
5876 DBSTATISTICS_FIELD(locks.num_pending),
5877 DBSTATISTICS_FIELD(locks.num_failed),
5878 DBSTATISTICS_FIELD(db_ro_delegations),
5881 static void print_dbstatistics(const char *db_name,
5882 struct ctdb_db_statistics *s)
5885 const char *prefix = NULL;
5888 printf("DB Statistics %s\n", db_name);
5890 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5891 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5892 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5894 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5895 prefix = db_stats_fields[i].name;
5896 printf(" %*.*s\n", preflen-1, preflen-1,
5897 db_stats_fields[i].name);
5902 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5903 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5904 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5907 printf(" hop_count_buckets:");
5908 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5909 printf(" %d", s->hop_count_bucket[i]);
5913 printf(" lock_buckets:");
5914 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5915 printf(" %d", s->locks.buckets[i]);
5919 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5920 "locks_latency MIN/AVG/MAX",
5921 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5922 s->locks.latency.max, s->locks.latency.num);
5924 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5925 "vacuum_latency MIN/AVG/MAX",
5926 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5927 s->vacuum.latency.max, s->vacuum.latency.num);
5929 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5930 for (i=0; i<s->num_hot_keys; i++) {
5932 printf(" Count:%d Key:", s->hot_keys[i].count);
5933 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5934 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5940 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5941 int argc, const char **argv)
5944 const char *db_name;
5945 struct ctdb_db_statistics *dbstats;
5949 usage("dbstatistics");
5952 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5956 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5957 ctdb->cmd_pnn, TIMEOUT(), db_id,
5960 fprintf(stderr, "Failed to get statistics for DB %s\n",
5965 print_dbstatistics(db_name, dbstats);
5969 struct disable_takeover_runs_state {
5977 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5980 struct disable_takeover_runs_state *state =
5981 (struct disable_takeover_runs_state *)private_data;
5984 if (data.dsize != sizeof(int)) {
5989 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5990 ret = *(int *)data.dptr;
5992 state->status = ret;
5996 for (i=0; i<state->node_count; i++) {
5997 if (state->pnn_list[i] == ret) {
5998 state->reply[i] = true;
6004 for (i=0; i<state->node_count; i++) {
6005 if (! state->reply[i]) {
6006 state->done = false;
6012 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
6013 struct ctdb_context *ctdb, uint32_t timeout,
6014 uint32_t *pnn_list, int count)
6016 struct ctdb_disable_message disable = { 0 };
6017 struct disable_takeover_runs_state state;
6020 disable.pnn = ctdb->pnn;
6021 disable.srvid = next_srvid(ctdb);
6022 disable.timeout = timeout;
6024 state.pnn_list = pnn_list;
6025 state.node_count = count;
6028 state.reply = talloc_zero_array(mem_ctx, bool, count);
6029 if (state.reply == NULL) {
6033 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
6035 disable_takeover_run_handler,
6041 for (i=0; i<count; i++) {
6042 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
6051 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
6053 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
6055 ret = (state.status >= 0 ? 0 : 1);
6059 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
6060 disable.srvid, &state);
6064 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
6065 int argc, const char **argv)
6067 const char *nodestring = NULL;
6068 struct ctdb_node_map *nodemap, *nodemap2;
6069 struct ctdb_req_control request;
6070 uint32_t *pnn_list, *pnn_list2;
6071 int ret, count, count2;
6078 nodestring = argv[0];
6081 nodemap = get_nodemap(ctdb, false);
6082 if (nodemap == NULL) {
6086 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
6090 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
6091 mem_ctx, &pnn_list);
6093 fprintf(stderr, "Memory allocation error\n");
6097 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
6098 mem_ctx, &pnn_list2);
6100 fprintf(stderr, "Memory allocation error\n");
6104 /* Disable takeover runs on all connected nodes. A reply
6105 * indicating success is needed from each node so all nodes
6106 * will need to be active.
6108 * A check could be added to not allow reloading of IPs when
6109 * there are disconnected nodes. However, this should
6110 * probably be left up to the administrator.
6112 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
6115 fprintf(stderr, "Failed to disable takeover runs\n");
6119 /* Now tell all the desired nodes to reload their public IPs.
6120 * Keep trying this until it succeeds. This assumes all
6121 * failures are transient, which might not be true...
6123 ctdb_req_control_reload_public_ips(&request);
6124 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
6125 pnn_list2, count2, TIMEOUT(),
6126 &request, NULL, NULL);
6128 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
6131 /* It isn't strictly necessary to wait until takeover runs are
6132 * re-enabled but doing so can't hurt.
6134 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
6136 fprintf(stderr, "Failed to enable takeover runs\n");
6140 return ipreallocate(mem_ctx, ctdb);
6143 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
6144 int argc, const char **argv)
6146 ctdb_sock_addr addr;
6153 if (! parse_ip(argv[0], NULL, 0, &addr)) {
6154 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
6158 iface = ctdb_sys_find_ifname(&addr);
6159 if (iface == NULL) {
6160 fprintf(stderr, "Failed to find interface for IP %s\n",
6170 static const struct ctdb_cmd {
6172 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
6173 bool without_daemon; /* can be run without daemon running ? */
6174 bool remote; /* can be run on remote nodes */
6177 } ctdb_commands[] = {
6178 { "version", control_version, true, false,
6179 "show version of ctdb", NULL },
6180 { "status", control_status, false, true,
6181 "show node status", NULL },
6182 { "uptime", control_uptime, false, true,
6183 "show node uptime", NULL },
6184 { "ping", control_ping, false, true,
6185 "ping all nodes", NULL },
6186 { "runstate", control_runstate, false, true,
6187 "get/check runstate of a node",
6188 "[setup|first_recovery|startup|running]" },
6189 { "getvar", control_getvar, false, true,
6190 "get a tunable variable", "<name>" },
6191 { "setvar", control_setvar, false, true,
6192 "set a tunable variable", "<name> <value>" },
6193 { "listvars", control_listvars, false, true,
6194 "list tunable variables", NULL },
6195 { "statistics", control_statistics, false, true,
6196 "show ctdb statistics", NULL },
6197 { "statisticsreset", control_statistics_reset, false, true,
6198 "reset ctdb statistics", NULL },
6199 { "stats", control_stats, false, true,
6200 "show rolling statistics", "[count]" },
6201 { "ip", control_ip, false, true,
6202 "show public ips", "[all]" },
6203 { "ipinfo", control_ipinfo, false, true,
6204 "show public ip details", "<ip>" },
6205 { "ifaces", control_ifaces, false, true,
6206 "show interfaces", NULL },
6207 { "setifacelink", control_setifacelink, false, true,
6208 "set interface link status", "<iface> up|down" },
6209 { "process-exists", control_process_exists, false, true,
6210 "check if a process exists on a node", "<pid>" },
6211 { "getdbmap", control_getdbmap, false, true,
6212 "show attached databases", NULL },
6213 { "getdbstatus", control_getdbstatus, false, true,
6214 "show database status", "<dbname|dbid>" },
6215 { "catdb", control_catdb, false, false,
6216 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6217 { "cattdb", control_cattdb, false, false,
6218 "dump local ctdb database", "<dbname|dbid>" },
6219 { "getmonmode", control_getmonmode, false, true,
6220 "show monitoring mode", NULL },
6221 { "getcapabilities", control_getcapabilities, false, true,
6222 "show node capabilities", NULL },
6223 { "pnn", control_pnn, false, false,
6224 "show the pnn of the currnet node", NULL },
6225 { "lvs", control_lvs, false, false,
6226 "show lvs configuration", "master|list|status" },
6227 { "disablemonitor", control_disable_monitor, false, true,
6228 "disable monitoring", NULL },
6229 { "enablemonitor", control_enable_monitor, false, true,
6230 "enable monitoring", NULL },
6231 { "setdebug", control_setdebug, false, true,
6232 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6233 { "getdebug", control_getdebug, false, true,
6234 "get debug level", NULL },
6235 { "attach", control_attach, false, false,
6236 "attach a database", "<dbname> [persistent]" },
6237 { "detach", control_detach, false, false,
6238 "detach database(s)", "<dbname|dbid> ..." },
6239 { "dumpmemory", control_dumpmemory, false, true,
6240 "dump ctdbd memory map", NULL },
6241 { "rddumpmemory", control_rddumpmemory, false, true,
6242 "dump recoverd memory map", NULL },
6243 { "getpid", control_getpid, false, true,
6244 "get ctdbd process ID", NULL },
6245 { "disable", control_disable, false, true,
6246 "disable a node", NULL },
6247 { "enable", control_enable, false, true,
6248 "enable a node", NULL },
6249 { "stop", control_stop, false, true,
6250 "stop a node", NULL },
6251 { "continue", control_continue, false, true,
6252 "continue a stopped node", NULL },
6253 { "ban", control_ban, false, true,
6254 "ban a node", "<bantime>"},
6255 { "unban", control_unban, false, true,
6256 "unban a node", NULL },
6257 { "shutdown", control_shutdown, false, true,
6258 "shutdown ctdb daemon", NULL },
6259 { "recover", control_recover, false, true,
6260 "force recovery", NULL },
6261 { "sync", control_ipreallocate, false, true,
6262 "run ip reallocation (deprecated)", NULL },
6263 { "ipreallocate", control_ipreallocate, false, true,
6264 "run ip reallocation", NULL },
6265 { "isnotrecmaster", control_isnotrecmaster, false, false,
6266 "check if local node is the recmaster", NULL },
6267 { "gratarp", control_gratarp, false, true,
6268 "send a gratuitous arp", "<ip> <interface>" },
6269 { "tickle", control_tickle, true, false,
6270 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6271 { "gettickles", control_gettickles, false, true,
6272 "get the list of tickles", "<ip> [<port>]" },
6273 { "addtickle", control_addtickle, false, true,
6274 "add a tickle", "<ip>:<port> <ip>:<port>" },
6275 { "deltickle", control_deltickle, false, true,
6276 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6277 { "check_srvids", control_check_srvids, false, true,
6278 "check if srvid is registered", "<id> [<id> ...]" },
6279 { "listnodes", control_listnodes, true, true,
6280 "list nodes in the cluster", NULL },
6281 { "reloadnodes", control_reloadnodes, false, false,
6282 "reload the nodes file all nodes", NULL },
6283 { "moveip", control_moveip, false, false,
6284 "move an ip address to another node", "<ip> <node>" },
6285 { "addip", control_addip, false, true,
6286 "add an ip address to a node", "<ip/mask> <iface>" },
6287 { "delip", control_delip, false, true,
6288 "delete an ip address from a node", "<ip>" },
6289 { "eventscript", control_eventscript, false, true,
6290 "run an event", "monitor" },
6291 { "backupdb", control_backupdb, false, false,
6292 "backup a database into a file", "<dbname|dbid> <file>" },
6293 { "restoredb", control_restoredb, false, false,
6294 "restore a database from a file", "<file> [dbname]" },
6295 { "dumpdbbackup", control_dumpdbbackup, true, false,
6296 "dump database from a backup file", "<file>" },
6297 { "wipedb", control_wipedb, false, false,
6298 "wipe the contents of a database.", "<dbname|dbid>"},
6299 { "recmaster", control_recmaster, false, true,
6300 "show the pnn for the recovery master", NULL },
6301 { "scriptstatus", control_scriptstatus, false, true,
6302 "show event script status",
6303 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6304 { "enablescript", control_enablescript, false, true,
6305 "enable an eventscript", "<script>"},
6306 { "disablescript", control_disablescript, false, true,
6307 "disable an eventscript", "<script>"},
6308 { "natgw", control_natgw, false, false,
6309 "show natgw configuration", "master|list|status" },
6310 { "natgwlist", control_natgwlist, false, false,
6311 "show the nodes belonging to this natgw configuration", NULL },
6312 { "getreclock", control_getreclock, false, true,
6313 "get recovery lock file", NULL },
6314 { "setlmasterrole", control_setlmasterrole, false, true,
6315 "set LMASTER role", "on|off" },
6316 { "setrecmasterrole", control_setrecmasterrole, false, true,
6317 "set RECMASTER role", "on|off"},
6318 { "setdbreadonly", control_setdbreadonly, false, true,
6319 "enable readonly records", "<dbname|dbid>" },
6320 { "setdbsticky", control_setdbsticky, false, true,
6321 "enable sticky records", "<dbname|dbid>"},
6322 { "pfetch", control_pfetch, false, false,
6323 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6324 { "pstore", control_pstore, false, false,
6325 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6326 { "pdelete", control_pdelete, false, false,
6327 "delete record from persistent database", "<dbname|dbid> <key>" },
6328 { "ptrans", control_ptrans, false, false,
6329 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6330 { "tfetch", control_tfetch, false, true,
6331 "fetch a record", "<tdb-file> <key> [<file>]" },
6332 { "tstore", control_tstore, false, true,
6333 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6334 { "readkey", control_readkey, false, false,
6335 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6336 { "writekey", control_writekey, false, false,
6337 "write value for a database key", "<dbname|dbid> <key> <value>" },
6338 { "deletekey", control_deletekey, false, false,
6339 "delete a database key", "<dbname|dbid> <key>" },
6340 { "checktcpport", control_checktcpport, true, false,
6341 "check if a service is bound to a specific tcp port or not", "<port>" },
6342 { "getdbseqnum", control_getdbseqnum, false, false,
6343 "get database sequence number", "<dbname|dbid>" },
6344 { "nodestatus", control_nodestatus, false, true,
6345 "show and return node status", "[all|<pnn-list>]" },
6346 { "dbstatistics", control_dbstatistics, false, true,
6347 "show database statistics", "<dbname|dbid>" },
6348 { "reloadips", control_reloadips, false, false,
6349 "reload the public addresses file", "[all|<pnn-list>]" },
6350 { "ipiface", control_ipiface, true, false,
6351 "Find the interface an ip address is hosted on", "<ip>" },
6354 static const struct ctdb_cmd *match_command(const char *command)
6356 const struct ctdb_cmd *cmd;
6359 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6360 cmd = &ctdb_commands[i];
6361 if (strlen(command) == strlen(cmd->name) &&
6362 strncmp(command, cmd->name, strlen(command)) == 0) {
6372 * Show usage message
6374 static void usage_full(void)
6378 poptPrintHelp(pc, stdout, 0);
6379 printf("\nCommands:\n");
6380 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6381 printf(" %-15s %-27s %s\n",
6382 ctdb_commands[i].name,
6383 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6384 ctdb_commands[i].msg);
6388 static void usage(const char *command)
6390 const struct ctdb_cmd *cmd;
6392 if (command == NULL) {
6397 cmd = match_command(command);
6401 poptPrintUsage(pc, stdout, 0);
6402 printf("\nCommands:\n");
6403 printf(" %-15s %-27s %s\n",
6404 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6410 struct poptOption cmdline_options[] = {
6412 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6413 "CTDB socket path", "filename" },
6414 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6416 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6417 "timelimit (in seconds)" },
6418 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6419 "node specification - integer" },
6420 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6421 "enable machine readable output", NULL },
6422 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6423 "specify separator for machine readable output", "CHAR" },
6424 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6425 "enable machine parsable output with separator |", NULL },
6426 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6427 "enable verbose output", NULL },
6428 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6429 "die if runtime exceeds this limit (in seconds)" },
6433 static int process_command(const struct ctdb_cmd *cmd, int argc,
6436 TALLOC_CTX *tmp_ctx;
6437 struct ctdb_context *ctdb;
6440 uint64_t srvid_offset;
6442 tmp_ctx = talloc_new(NULL);
6443 if (tmp_ctx == NULL) {
6444 fprintf(stderr, "Memory allocation error\n");
6448 if (cmd->without_daemon) {
6449 if (options.pnn != -1) {
6451 "Cannot specify node for command %s\n",
6456 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6457 talloc_free(tmp_ctx);
6461 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6463 fprintf(stderr, "Memory allocation error\n");
6467 ctdb->ev = tevent_context_init(ctdb);
6468 if (ctdb->ev == NULL) {
6469 fprintf(stderr, "Failed to initialize tevent\n");
6473 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6475 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6478 if (!find_node_xpnn(ctdb, NULL)) {
6479 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6484 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6485 srvid_offset = getpid() & 0xFFFF;
6486 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6488 if (options.pnn != -1) {
6489 status = verify_pnn(ctdb, options.pnn);
6494 ctdb->cmd_pnn = options.pnn;
6496 ctdb->cmd_pnn = ctdb->pnn;
6499 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6500 fprintf(stderr, "Node cannot be specified for command %s\n",
6505 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6506 talloc_free(tmp_ctx);
6510 talloc_free(tmp_ctx);
6514 static void signal_handler(int sig)
6516 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6519 static void alarm_handler(int sig)
6521 /* Kill any child processes */
6522 signal(SIGTERM, signal_handler);
6528 int main(int argc, const char *argv[])
6531 const char **extra_argv;
6533 const struct ctdb_cmd *cmd;
6534 const char *ctdb_socket;
6540 /* Set default options */
6541 options.socket = CTDB_SOCKET;
6542 options.debuglevelstr = NULL;
6543 options.timelimit = 10;
6545 options.maxruntime = 0;
6548 ctdb_socket = getenv("CTDB_SOCKET");
6549 if (ctdb_socket != NULL) {
6550 options.socket = ctdb_socket;
6553 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6554 POPT_CONTEXT_KEEP_FIRST);
6555 while ((opt = poptGetNextOpt(pc)) != -1) {
6556 fprintf(stderr, "Invalid option %s: %s\n",
6557 poptBadOption(pc, 0), poptStrerror(opt));
6561 if (options.maxruntime == 0) {
6562 const char *ctdb_timeout;
6564 ctdb_timeout = getenv("CTDB_TIMEOUT");
6565 if (ctdb_timeout != NULL) {
6566 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6568 options.maxruntime = 120;
6571 if (options.maxruntime <= 120) {
6572 /* default timeout is 120 seconds */
6573 options.maxruntime = 120;
6576 if (options.machineparsable) {
6577 options.machinereadable = 1;
6580 /* setup the remaining options for the commands */
6582 extra_argv = poptGetArgs(pc);
6585 while (extra_argv[extra_argc]) extra_argc++;
6588 if (extra_argc < 1) {
6592 cmd = match_command(extra_argv[0]);
6594 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6598 /* Enable logging */
6599 setup_logging("ctdb", DEBUG_STDERR);
6600 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6601 DEBUGLEVEL = loglevel;
6603 DEBUGLEVEL = DEBUG_ERR;
6606 signal(SIGALRM, alarm_handler);
6607 alarm(options.maxruntime);
6609 ret = process_command(cmd, extra_argc, extra_argv);
6614 (void)poptFreeContext(pc);