pytest:security descriptors: hack to capture results as json
[Samba.git] / ctdb / tools / ctdb.c
blob67d2f6bc1c98fd5170b83044a909759ef3f6fe3d
1 /*
2 CTDB control tool
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/>.
20 #include "replace.h"
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
27 #include <ctype.h>
28 #include <popt.h>
29 #include <talloc.h>
30 #include <tevent.h>
31 #include <tdb.h>
33 #include "version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
37 #include "lib/util/smb_strtox.h"
39 #include "common/db_hash.h"
40 #include "common/logging.h"
41 #include "common/path.h"
42 #include "protocol/protocol.h"
43 #include "protocol/protocol_basic.h"
44 #include "protocol/protocol_api.h"
45 #include "protocol/protocol_util.h"
46 #include "common/system_socket.h"
47 #include "client/client.h"
48 #include "client/client_sync.h"
50 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
52 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
53 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
55 #define NODE_FLAGS_UNKNOWN 0x00000040
57 static struct {
58 const char *debuglevelstr;
59 int timelimit;
60 int pnn;
61 int machinereadable;
62 const char *sep;
63 int machineparsable;
64 int verbose;
65 int maxruntime;
66 int printemptyrecords;
67 int printdatasize;
68 int printlmaster;
69 int printhash;
70 int printrecordflags;
71 } options;
73 static poptContext pc;
75 struct ctdb_context {
76 struct tevent_context *ev;
77 struct ctdb_client_context *client;
78 struct ctdb_node_map *nodemap;
79 uint32_t pnn, cmd_pnn, leader_pnn;
80 uint64_t srvid;
83 static void usage(const char *command);
86 * Utility Functions
89 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
91 return (tv2->tv_sec - tv->tv_sec) +
92 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
95 static struct ctdb_node_and_flags *get_node_by_pnn(
96 struct ctdb_node_map *nodemap,
97 uint32_t pnn)
99 unsigned int i;
101 for (i=0; i<nodemap->num; i++) {
102 if (nodemap->node[i].pnn == pnn) {
103 return &nodemap->node[i];
106 return NULL;
109 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
111 static const struct {
112 uint32_t flag;
113 const char *name;
114 } flag_names[] = {
115 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
116 { NODE_FLAGS_UNKNOWN, "UNKNOWN" },
117 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
118 { NODE_FLAGS_BANNED, "BANNED" },
119 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
120 { NODE_FLAGS_DELETED, "DELETED" },
121 { NODE_FLAGS_STOPPED, "STOPPED" },
122 { NODE_FLAGS_INACTIVE, "INACTIVE" },
124 char *flags_str = NULL;
125 size_t i;
127 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
128 if (flags & flag_names[i].flag) {
129 if (flags_str == NULL) {
130 flags_str = talloc_asprintf(mem_ctx,
131 "%s", flag_names[i].name);
132 } else {
133 flags_str = talloc_asprintf_append(flags_str,
134 "|%s", flag_names[i].name);
136 if (flags_str == NULL) {
137 return "OUT-OF-MEMORY";
141 if (flags_str == NULL) {
142 return "OK";
145 return flags_str;
148 static uint64_t next_srvid(struct ctdb_context *ctdb)
150 ctdb->srvid += 1;
151 return ctdb->srvid;
155 * Get consistent nodemap information.
157 * If nodemap is already cached, use that. If not get it.
158 * If the current node is BANNED, then get nodemap from "better" node.
160 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
162 TALLOC_CTX *tmp_ctx;
163 struct ctdb_node_map *nodemap;
164 struct ctdb_node_and_flags *node;
165 uint32_t current_node;
166 int ret;
168 if (force) {
169 TALLOC_FREE(ctdb->nodemap);
172 if (ctdb->nodemap != NULL) {
173 return ctdb->nodemap;
176 tmp_ctx = talloc_new(ctdb);
177 if (tmp_ctx == NULL) {
178 return false;
181 current_node = ctdb->pnn;
182 again:
183 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
184 current_node, TIMEOUT(), &nodemap);
185 if (ret != 0) {
186 fprintf(stderr, "Failed to get nodemap from node %u\n",
187 current_node);
188 goto failed;
191 node = get_node_by_pnn(nodemap, current_node);
192 if (node->flags & NODE_FLAGS_BANNED) {
193 /* Pick next node */
194 do {
195 current_node = (current_node + 1) % nodemap->num;
196 node = get_node_by_pnn(nodemap, current_node);
197 if (! (node->flags &
198 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
199 break;
201 } while (current_node != ctdb->pnn);
203 if (current_node == ctdb->pnn) {
204 /* Tried all nodes in the cluster */
205 fprintf(stderr, "Warning: All nodes are banned.\n");
206 goto failed;
209 goto again;
212 ctdb->nodemap = talloc_steal(ctdb, nodemap);
213 return nodemap;
215 failed:
216 talloc_free(tmp_ctx);
217 return NULL;
220 static void print_pnn(uint32_t pnn)
222 if (pnn == CTDB_UNKNOWN_PNN) {
223 printf("UNKNOWN\n");
224 return;
227 printf("%u\n", pnn);
230 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
232 struct ctdb_node_map *nodemap;
233 bool found;
234 unsigned int i;
236 if (pnn == -1) {
237 return false;
240 nodemap = get_nodemap(ctdb, false);
241 if (nodemap == NULL) {
242 return false;
245 found = false;
246 for (i=0; i<nodemap->num; i++) {
247 if (nodemap->node[i].pnn == (uint32_t)pnn) {
248 found = true;
249 break;
252 if (! found) {
253 fprintf(stderr, "Node %u does not exist\n", pnn);
254 return false;
257 if (nodemap->node[i].flags &
258 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
259 fprintf(stderr, "Node %u has status %s\n", pnn,
260 pretty_print_flags(ctdb, nodemap->node[i].flags));
261 return false;
264 return true;
267 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
268 struct ctdb_node_map *nodemap)
270 struct ctdb_node_map *nodemap2;
272 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
273 if (nodemap2 == NULL) {
274 return NULL;
277 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
278 nodemap->num);
279 if (nodemap2->node == NULL) {
280 talloc_free(nodemap2);
281 return NULL;
284 return nodemap2;
288 * Get the number and the list of matching nodes
290 * nodestring := NULL | all | pnn,[pnn,...]
292 * If nodestring is NULL, use the current node.
294 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
295 const char *nodestring,
296 struct ctdb_node_map **out)
298 struct ctdb_node_map *nodemap, *nodemap2;
299 struct ctdb_node_and_flags *node;
300 unsigned int i;
302 nodemap = get_nodemap(ctdb, false);
303 if (nodemap == NULL) {
304 return false;
307 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
308 if (nodemap2 == NULL) {
309 return false;
312 if (nodestring == NULL) {
313 for (i=0; i<nodemap->num; i++) {
314 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
315 nodemap2->node[0] = nodemap->node[i];
316 break;
319 nodemap2->num = 1;
321 goto done;
324 if (strcmp(nodestring, "all") == 0) {
325 for (i=0; i<nodemap->num; i++) {
326 nodemap2->node[i] = nodemap->node[i];
328 nodemap2->num = nodemap->num;
330 goto done;
331 } else {
332 char *ns, *tok;
333 int error = 0;
335 ns = talloc_strdup(mem_ctx, nodestring);
336 if (ns == NULL) {
337 return false;
340 tok = strtok(ns, ",");
341 while (tok != NULL) {
342 uint32_t pnn;
344 pnn = (uint32_t)smb_strtoul(tok,
345 NULL,
347 &error,
348 SMB_STR_STANDARD);
349 if (error != 0) {
350 fprintf(stderr, "Invalid node %s\n", tok);
351 return false;
354 node = get_node_by_pnn(nodemap, pnn);
355 if (node == NULL) {
356 fprintf(stderr, "Node %u does not exist\n",
357 pnn);
358 return false;
361 nodemap2->node[nodemap2->num] = *node;
362 nodemap2->num += 1;
364 tok = strtok(NULL, ",");
368 done:
369 *out = nodemap2;
370 return true;
374 * Remote nodes are initialised as UNHEALTHY in the daemon and their
375 * true status is updated after they are connected. However, there
376 * is a small window when a healthy node may be shown as unhealthy
377 * between connecting and the status update. Hide this for nodes
378 * that are not DISCONNECTED nodes by reporting them as UNKNOWN until
379 * the runstate passes FIRST_RECOVERY. Code paths where this is used
380 * do not make any control decisions depending upon unknown/unhealthy
381 * state.
383 static struct ctdb_node_map *get_nodemap_unknown(
384 TALLOC_CTX *mem_ctx,
385 struct ctdb_context *ctdb,
386 struct ctdb_node_map *nodemap_in)
388 unsigned int i;
389 int ret;
390 enum ctdb_runstate runstate;
391 struct ctdb_node_map *nodemap;
393 ret = ctdb_ctrl_get_runstate(mem_ctx,
394 ctdb->ev,
395 ctdb->client,
396 ctdb->cmd_pnn,
397 TIMEOUT(),
398 &runstate);
399 if (ret != 0 ) {
400 printf("Unable to get runstate");
401 return NULL;
404 nodemap = talloc_nodemap(mem_ctx, nodemap_in);
405 if (nodemap == NULL) {
406 printf("Unable to get nodemap");
407 return NULL;
410 nodemap->num = nodemap_in->num;
411 for (i=0; i<nodemap->num; i++) {
412 struct ctdb_node_and_flags *node_in = &nodemap_in->node[i];
413 struct ctdb_node_and_flags *node = &nodemap->node[i];
415 *node = *node_in;
417 if (node->flags & NODE_FLAGS_DELETED) {
418 continue;
421 if ((runstate <= CTDB_RUNSTATE_FIRST_RECOVERY) &&
422 !(node->flags & NODE_FLAGS_DISCONNECTED) &&
423 (node->pnn != ctdb->cmd_pnn)) {
424 node->flags = NODE_FLAGS_UNKNOWN;
428 return nodemap;
431 /* Compare IP address */
432 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
434 bool ret = false;
436 if (ip1->sa.sa_family != ip2->sa.sa_family) {
437 return false;
440 switch (ip1->sa.sa_family) {
441 case AF_INET:
442 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
443 sizeof(struct in_addr)) == 0);
444 break;
446 case AF_INET6:
447 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
448 sizeof(struct in6_addr)) == 0);
449 break;
452 return ret;
455 /* Append a node to a node map with given address and flags */
456 static bool node_map_add(struct ctdb_node_map *nodemap,
457 const char *nstr, uint32_t flags)
459 ctdb_sock_addr addr;
460 uint32_t num;
461 struct ctdb_node_and_flags *n;
462 int ret;
464 ret = ctdb_sock_addr_from_string(nstr, &addr, false);
465 if (ret != 0) {
466 fprintf(stderr, "Invalid IP address %s\n", nstr);
467 return false;
470 num = nodemap->num;
471 nodemap->node = talloc_realloc(nodemap, nodemap->node,
472 struct ctdb_node_and_flags, num+1);
473 if (nodemap->node == NULL) {
474 return false;
477 n = &nodemap->node[num];
478 n->addr = addr;
479 n->pnn = num;
480 n->flags = flags;
482 nodemap->num = num+1;
483 return true;
486 /* Read a nodes file into a node map */
487 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
488 const char *nlist)
490 char **lines;
491 int nlines;
492 int i;
493 struct ctdb_node_map *nodemap;
495 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
496 if (nodemap == NULL) {
497 return NULL;
500 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
501 if (lines == NULL) {
502 return NULL;
505 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
506 nlines--;
509 for (i=0; i<nlines; i++) {
510 char *node;
511 uint32_t flags;
512 size_t len;
514 node = lines[i];
515 /* strip leading spaces */
516 while((*node == ' ') || (*node == '\t')) {
517 node++;
520 len = strlen(node);
522 /* strip trailing spaces */
523 while ((len > 1) &&
524 ((node[len-1] == ' ') || (node[len-1] == '\t')))
526 node[len-1] = '\0';
527 len--;
530 if (len == 0) {
531 continue;
533 if (*node == '#') {
534 /* A "deleted" node is a node that is
535 commented out in the nodes file. This is
536 used instead of removing a line, which
537 would cause subsequent nodes to change
538 their PNN. */
539 flags = NODE_FLAGS_DELETED;
540 node = discard_const("0.0.0.0");
541 } else {
542 flags = 0;
544 if (! node_map_add(nodemap, node, flags)) {
545 talloc_free(lines);
546 TALLOC_FREE(nodemap);
547 return NULL;
551 talloc_free(lines);
552 return nodemap;
555 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
557 struct ctdb_node_map *nodemap;
558 const char *nodes_list = NULL;
560 const char *basedir = getenv("CTDB_BASE");
561 if (basedir == NULL) {
562 basedir = CTDB_ETCDIR;
564 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
565 if (nodes_list == NULL) {
566 fprintf(stderr, "Memory allocation error\n");
567 return NULL;
570 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
571 if (nodemap == NULL) {
572 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
573 nodes_list);
574 return NULL;
577 return nodemap;
580 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
581 struct ctdb_context *ctdb,
582 struct ctdb_dbid_map *dbmap,
583 const char *db_name)
585 struct ctdb_dbid *db = NULL;
586 const char *name;
587 unsigned int i;
588 int ret;
590 for (i=0; i<dbmap->num; i++) {
591 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
592 ctdb->pnn, TIMEOUT(),
593 dbmap->dbs[i].db_id, &name);
594 if (ret != 0) {
595 return false;
598 if (strcmp(db_name, name) == 0) {
599 talloc_free(discard_const(name));
600 db = &dbmap->dbs[i];
601 break;
605 return db;
608 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
609 const char *db_arg, uint32_t *db_id,
610 const char **db_name, uint8_t *db_flags)
612 struct ctdb_dbid_map *dbmap;
613 struct ctdb_dbid *db = NULL;
614 uint32_t id = 0;
615 const char *name = NULL;
616 unsigned int i;
617 int ret = 0;
619 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
620 ctdb->pnn, TIMEOUT(), &dbmap);
621 if (ret != 0) {
622 return false;
625 if (strncmp(db_arg, "0x", 2) == 0) {
626 id = smb_strtoul(db_arg, NULL, 0, &ret, SMB_STR_STANDARD);
627 if (ret != 0) {
628 return false;
630 for (i=0; i<dbmap->num; i++) {
631 if (id == dbmap->dbs[i].db_id) {
632 db = &dbmap->dbs[i];
633 break;
636 } else {
637 name = db_arg;
638 db = db_find(mem_ctx, ctdb, dbmap, name);
641 if (db == NULL) {
642 fprintf(stderr, "No database matching '%s' found\n", db_arg);
643 return false;
646 if (name == NULL) {
647 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
648 ctdb->pnn, TIMEOUT(), id, &name);
649 if (ret != 0) {
650 return false;
654 if (db_id != NULL) {
655 *db_id = db->db_id;
657 if (db_name != NULL) {
658 *db_name = talloc_strdup(mem_ctx, name);
660 if (db_flags != NULL) {
661 *db_flags = db->flags;
663 return true;
666 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
667 TDB_DATA *out)
669 unsigned int i;
670 TDB_DATA data;
672 if (len & 0x01) {
673 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
674 str);
675 return EINVAL;
678 data.dsize = len / 2;
679 data.dptr = talloc_size(mem_ctx, data.dsize);
680 if (data.dptr == NULL) {
681 return ENOMEM;
684 for (i=0; i<data.dsize; i++) {
685 bool ok = hex_byte(&str[i*2], &data.dptr[i]);
686 if (!ok) {
687 fprintf(stderr, "Invalid hex: %s\n", &str[i*2]);
688 return EINVAL;
692 *out = data;
693 return 0;
696 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
697 TDB_DATA *out)
699 TDB_DATA data;
700 int ret = 0;
702 if (strncmp(str, "0x", 2) == 0) {
703 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
704 if (ret != 0) {
705 return ret;
707 } else {
708 data.dptr = talloc_memdup(mem_ctx, str, len);
709 if (data.dptr == NULL) {
710 return ENOMEM;
712 data.dsize = len;
715 *out = data;
716 return 0;
719 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
720 const char *path, int argc, const char **argv)
722 pid_t pid;
723 int save_errno, status, ret;
724 const char **new_argv;
725 int i;
727 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
728 if (new_argv == NULL) {
729 return ENOMEM;
732 new_argv[0] = path;
733 for (i=0; i<argc; i++) {
734 new_argv[i+1] = argv[i];
736 new_argv[argc+1] = NULL;
738 pid = fork();
739 if (pid < 0) {
740 save_errno = errno;
741 talloc_free(new_argv);
742 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
743 command, path, strerror(save_errno));
744 return save_errno;
747 if (pid == 0) {
748 ret = execv(path, discard_const(new_argv));
749 if (ret == -1) {
750 _exit(64+errno);
752 /* Should not happen */
753 _exit(64+ENOEXEC);
756 talloc_free(new_argv);
758 ret = waitpid(pid, &status, 0);
759 if (ret == -1) {
760 save_errno = errno;
761 fprintf(stderr, "waitpid() failed for %s - %s\n",
762 command, strerror(save_errno));
763 return save_errno;
766 if (WIFEXITED(status)) {
767 int pstatus = WEXITSTATUS(status);
768 if (WIFSIGNALED(status)) {
769 fprintf(stderr, "%s terminated with signal %d\n",
770 command, WTERMSIG(status));
771 ret = EINTR;
772 } else if (pstatus >= 64 && pstatus < 255) {
773 fprintf(stderr, "%s failed with error %d\n",
774 command, pstatus-64);
775 ret = pstatus - 64;
776 } else {
777 ret = pstatus;
779 return ret;
780 } else if (WIFSIGNALED(status)) {
781 fprintf(stderr, "%s terminated with signal %d\n",
782 command, WTERMSIG(status));
783 return EINTR;
786 return 0;
789 static void leader_handler(uint64_t srvid,
790 TDB_DATA data,
791 void *private_data)
793 struct ctdb_context *ctdb = talloc_get_type_abort(
794 private_data, struct ctdb_context);
795 uint32_t leader_pnn;
796 size_t np;
797 int ret;
799 ret = ctdb_uint32_pull(data.dptr, data.dsize, &leader_pnn, &np);
800 if (ret != 0) {
801 /* Ignore packet */
802 return;
805 ctdb->leader_pnn = leader_pnn;
808 static bool get_leader_done(void *private_data)
810 struct ctdb_context *ctdb = talloc_get_type_abort(
811 private_data, struct ctdb_context);
813 return ctdb->leader_pnn != CTDB_UNKNOWN_PNN;
816 static int get_leader(TALLOC_CTX *mem_ctx,
817 struct ctdb_context *ctdb,
818 uint32_t *leader)
820 int ret;
822 ret = ctdb_client_wait_func_timeout(ctdb->ev,
823 get_leader_done,
824 ctdb,
825 TIMEOUT());
827 * If ETIMEDOUT then assume there is no leader and succeed so
828 * initial value of CTDB_UNKNOWN_PNN is returned
830 if (ret == ETIMEDOUT) {
831 ret = 0;
832 } else if (ret != 0) {
833 fprintf(stderr, "Error getting leader\n");
834 return ret;
837 *leader = ctdb->leader_pnn;
838 return 0;
842 * Command Functions
845 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
846 int argc, const char **argv)
848 printf("%s\n", SAMBA_VERSION_STRING);
849 return 0;
852 static bool partially_online(TALLOC_CTX *mem_ctx,
853 struct ctdb_context *ctdb,
854 struct ctdb_node_and_flags *node)
856 struct ctdb_iface_list *iface_list;
857 unsigned int i;
858 int ret;
859 bool status = false;
861 if (node->flags != 0) {
862 return false;
865 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
866 node->pnn, TIMEOUT(), &iface_list);
867 if (ret != 0) {
868 return false;
871 status = false;
872 for (i=0; i < iface_list->num; i++) {
873 if (iface_list->iface[i].link_state == 0) {
874 status = true;
875 break;
879 return status;
882 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
883 struct ctdb_context *ctdb,
884 struct ctdb_node_map *nodemap,
885 uint32_t mypnn)
887 struct ctdb_node_and_flags *node;
888 unsigned int i;
890 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
891 options.sep,
892 "Node", options.sep,
893 "IP", options.sep,
894 "Disconnected", options.sep,
895 "Unknown", options.sep,
896 "Banned", options.sep,
897 "Disabled", options.sep,
898 "Unhealthy", options.sep,
899 "Stopped", options.sep,
900 "Inactive", options.sep,
901 "PartiallyOnline", options.sep,
902 "ThisNode", options.sep);
904 for (i=0; i<nodemap->num; i++) {
905 node = &nodemap->node[i];
906 if (node->flags & NODE_FLAGS_DELETED) {
907 continue;
910 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
911 options.sep,
912 node->pnn, options.sep,
913 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
914 options.sep,
915 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
916 !! (node->flags & NODE_FLAGS_UNKNOWN), options.sep,
917 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
918 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
919 options.sep,
920 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
921 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
922 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
923 partially_online(mem_ctx, ctdb, node), options.sep,
924 (node->pnn == mypnn)?'Y':'N', options.sep);
929 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
930 struct ctdb_node_map *nodemap, uint32_t mypnn,
931 bool print_header)
933 struct ctdb_node_and_flags *node;
934 int num_deleted_nodes = 0;
935 unsigned int i;
937 for (i=0; i<nodemap->num; i++) {
938 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
939 num_deleted_nodes++;
943 if (print_header) {
944 if (num_deleted_nodes == 0) {
945 printf("Number of nodes:%d\n", nodemap->num);
946 } else {
947 printf("Number of nodes:%d "
948 "(including %d deleted nodes)\n",
949 nodemap->num, num_deleted_nodes);
953 for (i=0; i<nodemap->num; i++) {
954 node = &nodemap->node[i];
955 if (node->flags & NODE_FLAGS_DELETED) {
956 continue;
959 printf("pnn:%u %-16s %s%s\n",
960 node->pnn,
961 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
962 partially_online(mem_ctx, ctdb, node) ?
963 "PARTIALLYONLINE" :
964 pretty_print_flags(mem_ctx, node->flags),
965 node->pnn == mypnn ? " (THIS NODE)" : "");
969 static void print_status(TALLOC_CTX *mem_ctx,
970 struct ctdb_context *ctdb,
971 struct ctdb_node_map *nodemap,
972 uint32_t mypnn,
973 struct ctdb_vnn_map *vnnmap,
974 int recmode,
975 uint32_t leader)
977 unsigned int i;
979 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
981 if (vnnmap->generation == INVALID_GENERATION) {
982 printf("Generation:INVALID\n");
983 } else {
984 printf("Generation:%u\n", vnnmap->generation);
986 printf("Size:%d\n", vnnmap->size);
987 for (i=0; i<vnnmap->size; i++) {
988 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
991 printf("Recovery mode:%s (%d)\n",
992 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
993 recmode);
994 printf("Leader:");
995 print_pnn(leader);
998 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
999 int argc, const char **argv)
1001 struct ctdb_node_map *nodemap_in;
1002 struct ctdb_node_map *nodemap;
1003 struct ctdb_vnn_map *vnnmap;
1004 int recmode;
1005 uint32_t leader;
1006 int ret;
1008 if (argc != 0) {
1009 usage("status");
1012 nodemap_in = get_nodemap(ctdb, false);
1013 if (nodemap_in == NULL) {
1014 return 1;
1017 nodemap = get_nodemap_unknown(mem_ctx, ctdb, nodemap_in);
1018 if (nodemap == NULL) {
1019 return 1;
1022 if (options.machinereadable == 1) {
1023 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
1024 return 0;
1027 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
1028 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
1029 if (ret != 0) {
1030 return ret;
1033 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
1034 ctdb->cmd_pnn, TIMEOUT(), &recmode);
1035 if (ret != 0) {
1036 return ret;
1039 ret = get_leader(mem_ctx, ctdb, &leader);
1040 if (ret != 0) {
1041 return ret;
1044 print_status(mem_ctx,
1045 ctdb,
1046 nodemap,
1047 ctdb->cmd_pnn,
1048 vnnmap,
1049 recmode,
1050 leader);
1051 return 0;
1054 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1055 int argc, const char **argv)
1057 struct ctdb_uptime *uptime;
1058 int ret, tmp, days, hours, minutes, seconds;
1060 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
1061 ctdb->cmd_pnn, TIMEOUT(), &uptime);
1062 if (ret != 0) {
1063 return ret;
1066 printf("Current time of node %-4u : %s",
1067 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
1069 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
1070 seconds = tmp % 60; tmp /= 60;
1071 minutes = tmp % 60; tmp /= 60;
1072 hours = tmp % 24; tmp /= 24;
1073 days = tmp;
1075 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
1076 days, hours, minutes, seconds,
1077 ctime(&uptime->ctdbd_start_time.tv_sec));
1079 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
1080 seconds = tmp % 60; tmp /= 60;
1081 minutes = tmp % 60; tmp /= 60;
1082 hours = tmp % 24; tmp /= 24;
1083 days = tmp;
1085 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
1086 days, hours, minutes, seconds,
1087 ctime(&uptime->last_recovery_finished.tv_sec));
1089 printf("Duration of last recovery/failover: %lf seconds\n",
1090 timeval_delta(&uptime->last_recovery_finished,
1091 &uptime->last_recovery_started));
1093 return 0;
1096 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1097 int argc, const char **argv)
1099 struct timeval tv;
1100 int ret, num_clients;
1102 tv = timeval_current();
1103 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
1104 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
1105 if (ret != 0) {
1106 return ret;
1109 printf("response from %u time=%.6f sec (%d clients)\n",
1110 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
1111 return 0;
1114 const char *runstate_to_string(enum ctdb_runstate runstate);
1115 enum ctdb_runstate runstate_from_string(const char *runstate_str);
1117 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1118 int argc, const char **argv)
1120 enum ctdb_runstate runstate;
1121 bool found;
1122 int ret, i;
1124 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
1125 ctdb->cmd_pnn, TIMEOUT(), &runstate);
1126 if (ret != 0) {
1127 return ret;
1130 found = true;
1131 for (i=0; i<argc; i++) {
1132 enum ctdb_runstate t;
1134 found = false;
1135 t = ctdb_runstate_from_string(argv[i]);
1136 if (t == CTDB_RUNSTATE_UNKNOWN) {
1137 printf("Invalid run state (%s)\n", argv[i]);
1138 return 1;
1141 if (t == runstate) {
1142 found = true;
1143 break;
1147 if (! found) {
1148 printf("CTDB not in required run state (got %s)\n",
1149 ctdb_runstate_to_string(runstate));
1150 return 1;
1153 printf("%s\n", ctdb_runstate_to_string(runstate));
1154 return 0;
1157 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1158 int argc, const char **argv)
1160 struct ctdb_var_list *tun_var_list;
1161 uint32_t value;
1162 int ret, i;
1163 bool found;
1165 if (argc != 1) {
1166 usage("getvar");
1169 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1170 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1171 if (ret != 0) {
1172 fprintf(stderr,
1173 "Failed to get list of variables from node %u\n",
1174 ctdb->cmd_pnn);
1175 return ret;
1178 found = false;
1179 for (i=0; i<tun_var_list->count; i++) {
1180 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1181 found = true;
1182 break;
1186 if (! found) {
1187 printf("No such tunable %s\n", argv[0]);
1188 return 1;
1191 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1192 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1193 if (ret != 0) {
1194 return ret;
1197 printf("%-26s = %u\n", argv[0], value);
1198 return 0;
1201 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1202 int argc, const char **argv)
1204 struct ctdb_var_list *tun_var_list;
1205 struct ctdb_tunable tunable;
1206 bool found;
1207 int i;
1208 int ret = 0;
1210 if (argc != 2) {
1211 usage("setvar");
1214 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1215 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1216 if (ret != 0) {
1217 fprintf(stderr,
1218 "Failed to get list of variables from node %u\n",
1219 ctdb->cmd_pnn);
1220 return ret;
1223 found = false;
1224 for (i=0; i<tun_var_list->count; i++) {
1225 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1226 found = true;
1227 break;
1231 if (! found) {
1232 printf("No such tunable %s\n", argv[0]);
1233 return 1;
1236 tunable.name = argv[0];
1237 tunable.value = smb_strtoul(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
1238 if (ret != 0) {
1239 return ret;
1242 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1243 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1244 if (ret != 0) {
1245 if (ret == 1) {
1246 fprintf(stderr,
1247 "Setting obsolete tunable variable '%s'\n",
1248 tunable.name);
1249 return 0;
1253 return ret;
1256 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1257 int argc, const char **argv)
1259 struct ctdb_var_list *tun_var_list;
1260 int ret, i;
1262 if (argc != 0) {
1263 usage("listvars");
1266 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1267 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1268 if (ret != 0) {
1269 return ret;
1272 for (i=0; i<tun_var_list->count; i++) {
1273 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1276 return 0;
1279 const struct {
1280 const char *name;
1281 uint32_t offset;
1282 } stats_fields[] = {
1283 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1284 STATISTICS_FIELD(num_clients),
1285 STATISTICS_FIELD(frozen),
1286 STATISTICS_FIELD(recovering),
1287 STATISTICS_FIELD(num_recoveries),
1288 STATISTICS_FIELD(client_packets_sent),
1289 STATISTICS_FIELD(client_packets_recv),
1290 STATISTICS_FIELD(node_packets_sent),
1291 STATISTICS_FIELD(node_packets_recv),
1292 STATISTICS_FIELD(keepalive_packets_sent),
1293 STATISTICS_FIELD(keepalive_packets_recv),
1294 STATISTICS_FIELD(node.req_call),
1295 STATISTICS_FIELD(node.reply_call),
1296 STATISTICS_FIELD(node.req_dmaster),
1297 STATISTICS_FIELD(node.reply_dmaster),
1298 STATISTICS_FIELD(node.reply_error),
1299 STATISTICS_FIELD(node.req_message),
1300 STATISTICS_FIELD(node.req_control),
1301 STATISTICS_FIELD(node.reply_control),
1302 STATISTICS_FIELD(node.req_tunnel),
1303 STATISTICS_FIELD(client.req_call),
1304 STATISTICS_FIELD(client.req_message),
1305 STATISTICS_FIELD(client.req_control),
1306 STATISTICS_FIELD(client.req_tunnel),
1307 STATISTICS_FIELD(timeouts.call),
1308 STATISTICS_FIELD(timeouts.control),
1309 STATISTICS_FIELD(timeouts.traverse),
1310 STATISTICS_FIELD(locks.num_calls),
1311 STATISTICS_FIELD(locks.num_current),
1312 STATISTICS_FIELD(locks.num_pending),
1313 STATISTICS_FIELD(locks.num_failed),
1314 STATISTICS_FIELD(total_calls),
1315 STATISTICS_FIELD(pending_calls),
1316 STATISTICS_FIELD(childwrite_calls),
1317 STATISTICS_FIELD(pending_childwrite_calls),
1318 STATISTICS_FIELD(memory_used),
1319 STATISTICS_FIELD(max_hop_count),
1320 STATISTICS_FIELD(total_ro_delegations),
1321 STATISTICS_FIELD(total_ro_revokes),
1324 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1326 static void print_statistics_machine(struct ctdb_statistics *s,
1327 bool show_header)
1329 size_t i;
1331 if (show_header) {
1332 printf("CTDB version%s", options.sep);
1333 printf("Current time of statistics%s", options.sep);
1334 printf("Statistics collected since%s", options.sep);
1335 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1336 printf("%s%s", stats_fields[i].name, options.sep);
1338 printf("num_reclock_ctdbd_latency%s", options.sep);
1339 printf("min_reclock_ctdbd_latency%s", options.sep);
1340 printf("avg_reclock_ctdbd_latency%s", options.sep);
1341 printf("max_reclock_ctdbd_latency%s", options.sep);
1343 printf("num_reclock_recd_latency%s", options.sep);
1344 printf("min_reclock_recd_latency%s", options.sep);
1345 printf("avg_reclock_recd_latency%s", options.sep);
1346 printf("max_reclock_recd_latency%s", options.sep);
1348 printf("num_call_latency%s", options.sep);
1349 printf("min_call_latency%s", options.sep);
1350 printf("avg_call_latency%s", options.sep);
1351 printf("max_call_latency%s", options.sep);
1353 printf("num_lockwait_latency%s", options.sep);
1354 printf("min_lockwait_latency%s", options.sep);
1355 printf("avg_lockwait_latency%s", options.sep);
1356 printf("max_lockwait_latency%s", options.sep);
1358 printf("num_childwrite_latency%s", options.sep);
1359 printf("min_childwrite_latency%s", options.sep);
1360 printf("avg_childwrite_latency%s", options.sep);
1361 printf("max_childwrite_latency%s", options.sep);
1362 printf("\n");
1365 printf("%u%s", CTDB_PROTOCOL, options.sep);
1366 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1367 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1368 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1369 printf("%u%s",
1370 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1371 options.sep);
1373 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1374 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1375 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1376 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1378 printf("%u%s", s->reclock.recd.num, options.sep);
1379 printf("%.6f%s", s->reclock.recd.min, options.sep);
1380 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1381 printf("%.6f%s", s->reclock.recd.max, options.sep);
1383 printf("%d%s", s->call_latency.num, options.sep);
1384 printf("%.6f%s", s->call_latency.min, options.sep);
1385 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1386 printf("%.6f%s", s->call_latency.max, options.sep);
1388 printf("%u%s", s->locks.latency.num, options.sep);
1389 printf("%.6f%s", s->locks.latency.min, options.sep);
1390 printf("%.6f%s", LATENCY_AVG(s->locks.latency), options.sep);
1391 printf("%.6f%s", s->locks.latency.max, options.sep);
1393 printf("%d%s", s->childwrite_latency.num, options.sep);
1394 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1395 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1396 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1397 printf("\n");
1400 static void print_statistics(struct ctdb_statistics *s)
1402 int tmp, days, hours, minutes, seconds;
1403 size_t i;
1404 const char *prefix = NULL;
1405 int preflen = 0;
1407 tmp = s->statistics_current_time.tv_sec -
1408 s->statistics_start_time.tv_sec;
1409 seconds = tmp % 60; tmp /= 60;
1410 minutes = tmp % 60; tmp /= 60;
1411 hours = tmp % 24; tmp /= 24;
1412 days = tmp;
1414 printf("CTDB version %u\n", CTDB_PROTOCOL);
1415 printf("Current time of statistics : %s",
1416 ctime(&s->statistics_current_time.tv_sec));
1417 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1418 days, hours, minutes, seconds,
1419 ctime(&s->statistics_start_time.tv_sec));
1421 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1422 if (strchr(stats_fields[i].name, '.') != NULL) {
1423 preflen = strcspn(stats_fields[i].name, ".") + 1;
1424 if (! prefix ||
1425 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1426 prefix = stats_fields[i].name;
1427 printf(" %*.*s\n", preflen-1, preflen-1,
1428 stats_fields[i].name);
1430 } else {
1431 preflen = 0;
1433 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1434 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1435 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1438 printf(" hop_count_buckets:");
1439 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1440 printf(" %d", s->hop_count_bucket[i]);
1442 printf("\n");
1443 printf(" lock_buckets:");
1444 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1445 printf(" %d", s->locks.buckets[i]);
1447 printf("\n");
1448 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1449 "locks_latency MIN/AVG/MAX",
1450 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1451 s->locks.latency.max, s->locks.latency.num);
1453 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1454 "reclock_ctdbd MIN/AVG/MAX",
1455 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1456 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1458 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1459 "reclock_recd MIN/AVG/MAX",
1460 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1461 s->reclock.recd.max, s->reclock.recd.num);
1463 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1464 "call_latency MIN/AVG/MAX",
1465 s->call_latency.min, LATENCY_AVG(s->call_latency),
1466 s->call_latency.max, s->call_latency.num);
1468 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1469 "childwrite_latency MIN/AVG/MAX",
1470 s->childwrite_latency.min,
1471 LATENCY_AVG(s->childwrite_latency),
1472 s->childwrite_latency.max, s->childwrite_latency.num);
1475 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1476 int argc, const char **argv)
1478 struct ctdb_statistics *stats;
1479 int ret;
1481 if (argc != 0) {
1482 usage("statistics");
1485 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1486 ctdb->cmd_pnn, TIMEOUT(), &stats);
1487 if (ret != 0) {
1488 return ret;
1491 if (options.machinereadable) {
1492 print_statistics_machine(stats, true);
1493 } else {
1494 print_statistics(stats);
1497 return 0;
1500 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1501 struct ctdb_context *ctdb,
1502 int argc, const char **argv)
1504 int ret;
1506 if (argc != 0) {
1507 usage("statisticsreset");
1510 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1511 ctdb->cmd_pnn, TIMEOUT());
1512 if (ret != 0) {
1513 return ret;
1516 return 0;
1519 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1520 int argc, const char **argv)
1522 struct ctdb_statistics_list *slist;
1523 int ret, count = 0, i;
1524 bool show_header = true;
1526 if (argc > 1) {
1527 usage("stats");
1530 if (argc == 1) {
1531 count = atoi(argv[0]);
1534 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1535 ctdb->cmd_pnn, TIMEOUT(), &slist);
1536 if (ret != 0) {
1537 return ret;
1540 for (i=0; i<slist->num; i++) {
1541 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1542 continue;
1544 if (options.machinereadable == 1) {
1545 print_statistics_machine(&slist->stats[i],
1546 show_header);
1547 show_header = false;
1548 } else {
1549 print_statistics(&slist->stats[i]);
1551 if (count > 0 && i == count) {
1552 break;
1556 return 0;
1559 static int ctdb_public_ip_cmp(const void *a, const void *b)
1561 const struct ctdb_public_ip *ip_a = a;
1562 const struct ctdb_public_ip *ip_b = b;
1564 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1567 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1568 struct ctdb_public_ip_list *ips,
1569 struct ctdb_public_ip_info **ipinfo,
1570 bool all_nodes)
1572 unsigned int i, j;
1573 char *conf, *avail, *active;
1575 if (options.machinereadable == 1) {
1576 printf("%s%s%s%s%s", options.sep,
1577 "Public IP", options.sep,
1578 "Node", options.sep);
1579 if (options.verbose == 1) {
1580 printf("%s%s%s%s%s%s\n",
1581 "ActiveInterfaces", options.sep,
1582 "AvailableInterfaces", options.sep,
1583 "ConfiguredInterfaces", options.sep);
1584 } else {
1585 printf("\n");
1587 } else {
1588 if (all_nodes) {
1589 printf("Public IPs on ALL nodes\n");
1590 } else {
1591 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1595 for (i = 0; i < ips->num; i++) {
1597 if (options.machinereadable == 1) {
1598 printf("%s%s%s%d%s", options.sep,
1599 ctdb_sock_addr_to_string(
1600 mem_ctx, &ips->ip[i].addr, false),
1601 options.sep,
1602 (int)ips->ip[i].pnn, options.sep);
1603 } else {
1604 printf("%s", ctdb_sock_addr_to_string(
1605 mem_ctx, &ips->ip[i].addr, false));
1608 if (options.verbose == 0) {
1609 if (options.machinereadable == 1) {
1610 printf("\n");
1611 } else {
1612 printf(" %d\n", (int)ips->ip[i].pnn);
1614 continue;
1617 conf = NULL;
1618 avail = NULL;
1619 active = NULL;
1621 if (ipinfo[i] == NULL) {
1622 goto skip_ipinfo;
1625 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1626 struct ctdb_iface *iface;
1628 iface = &ipinfo[i]->ifaces->iface[j];
1629 if (conf == NULL) {
1630 conf = talloc_strdup(mem_ctx, iface->name);
1631 } else {
1632 conf = talloc_asprintf_append(
1633 conf, ",%s", iface->name);
1636 if (ipinfo[i]->active_idx == j) {
1637 active = iface->name;
1640 if (iface->link_state == 0) {
1641 continue;
1644 if (avail == NULL) {
1645 avail = talloc_strdup(mem_ctx, iface->name);
1646 } else {
1647 avail = talloc_asprintf_append(
1648 avail, ",%s", iface->name);
1652 skip_ipinfo:
1654 if (options.machinereadable == 1) {
1655 printf("%s%s%s%s%s%s\n",
1656 active ? active : "", options.sep,
1657 avail ? avail : "", options.sep,
1658 conf ? conf : "", options.sep);
1659 } else {
1660 printf(" node[%d] active[%s] available[%s]"
1661 " configured[%s]\n",
1662 (int)ips->ip[i].pnn, active ? active : "",
1663 avail ? avail : "", conf ? conf : "");
1668 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1669 size_t datalen, void *private_data)
1671 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1672 private_data, struct ctdb_public_ip_list);
1673 struct ctdb_public_ip *ip;
1675 ip = (struct ctdb_public_ip *)databuf;
1676 ips->ip[ips->num] = *ip;
1677 ips->num += 1;
1679 return 0;
1682 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1683 struct ctdb_public_ip_list **out)
1685 struct ctdb_node_map *nodemap;
1686 struct ctdb_public_ip_list *ips;
1687 struct db_hash_context *ipdb;
1688 uint32_t *pnn_list;
1689 unsigned int j;
1690 int ret, count, i;
1692 nodemap = get_nodemap(ctdb, false);
1693 if (nodemap == NULL) {
1694 return 1;
1697 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1698 if (ret != 0) {
1699 goto failed;
1702 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1703 &pnn_list);
1704 if (count <= 0) {
1705 goto failed;
1708 for (i=0; i<count; i++) {
1709 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1710 pnn_list[i], TIMEOUT(),
1711 false, &ips);
1712 if (ret != 0) {
1713 goto failed;
1716 for (j=0; j<ips->num; j++) {
1717 struct ctdb_public_ip ip;
1719 ip.pnn = ips->ip[j].pnn;
1720 ip.addr = ips->ip[j].addr;
1722 if (pnn_list[i] == ip.pnn) {
1723 /* Node claims IP is hosted on it, so
1724 * save that information
1726 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1727 sizeof(ip.addr),
1728 (uint8_t *)&ip, sizeof(ip));
1729 if (ret != 0) {
1730 goto failed;
1732 } else {
1733 /* Node thinks IP is hosted elsewhere,
1734 * so overwrite with CTDB_UNKNOWN_PNN
1735 * if there's no existing entry
1737 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1738 sizeof(ip.addr));
1739 if (ret == ENOENT) {
1740 ip.pnn = CTDB_UNKNOWN_PNN;
1741 ret = db_hash_add(ipdb,
1742 (uint8_t *)&ip.addr,
1743 sizeof(ip.addr),
1744 (uint8_t *)&ip,
1745 sizeof(ip));
1746 if (ret != 0) {
1747 goto failed;
1753 TALLOC_FREE(ips);
1756 talloc_free(pnn_list);
1758 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1759 if (ret != 0) {
1760 goto failed;
1763 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1764 if (ips == NULL) {
1765 goto failed;
1768 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1769 if (ips->ip == NULL) {
1770 goto failed;
1773 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1774 if (ret != 0) {
1775 goto failed;
1778 if ((unsigned int)count != ips->num) {
1779 goto failed;
1782 talloc_free(ipdb);
1784 *out = ips;
1785 return 0;
1787 failed:
1788 talloc_free(ipdb);
1789 return 1;
1792 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1793 int argc, const char **argv)
1795 struct ctdb_public_ip_list *ips;
1796 struct ctdb_public_ip_info **ipinfo;
1797 unsigned int i;
1798 int ret;
1799 bool do_all = false;
1801 if (argc > 1) {
1802 usage("ip");
1805 if (argc == 1) {
1806 if (strcmp(argv[0], "all") == 0) {
1807 do_all = true;
1808 } else {
1809 usage("ip");
1813 if (do_all) {
1814 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1815 } else {
1816 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1817 ctdb->cmd_pnn, TIMEOUT(),
1818 false, &ips);
1820 if (ret != 0) {
1821 return ret;
1824 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1825 ctdb_public_ip_cmp);
1827 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1828 if (ipinfo == NULL) {
1829 return 1;
1832 for (i=0; i<ips->num; i++) {
1833 uint32_t pnn;
1834 if (do_all) {
1835 pnn = ips->ip[i].pnn;
1836 } else {
1837 pnn = ctdb->cmd_pnn;
1839 if (pnn == CTDB_UNKNOWN_PNN) {
1840 ipinfo[i] = NULL;
1841 continue;
1843 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1844 ctdb->client, pnn,
1845 TIMEOUT(), &ips->ip[i].addr,
1846 &ipinfo[i]);
1847 if (ret != 0) {
1848 return ret;
1852 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1853 return 0;
1856 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1857 int argc, const char **argv)
1859 struct ctdb_public_ip_info *ipinfo;
1860 ctdb_sock_addr addr;
1861 unsigned int i;
1862 int ret;
1864 if (argc != 1) {
1865 usage("ipinfo");
1868 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
1869 if (ret != 0) {
1870 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1871 return 1;
1874 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1875 ctdb->cmd_pnn, TIMEOUT(), &addr,
1876 &ipinfo);
1877 if (ret != 0) {
1878 if (ret == -1) {
1879 printf("Node %u does not know about IP %s\n",
1880 ctdb->cmd_pnn, argv[0]);
1882 return ret;
1885 printf("Public IP[%s] info on node %u\n",
1886 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1887 ctdb->cmd_pnn);
1889 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1890 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1891 ipinfo->ip.pnn, ipinfo->ifaces->num);
1893 for (i=0; i<ipinfo->ifaces->num; i++) {
1894 struct ctdb_iface *iface;
1896 iface = &ipinfo->ifaces->iface[i];
1897 iface->name[CTDB_IFACE_SIZE] = '\0';
1898 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1899 i+1, iface->name,
1900 iface->link_state == 0 ? "down" : "up",
1901 iface->references,
1902 (i == ipinfo->active_idx) ? " (active)" : "");
1905 return 0;
1908 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1909 int argc, const char **argv)
1911 struct ctdb_iface_list *ifaces;
1912 unsigned int i;
1913 int ret;
1915 if (argc != 0) {
1916 usage("ifaces");
1919 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1920 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1921 if (ret != 0) {
1922 return ret;
1925 if (ifaces->num == 0) {
1926 printf("No interfaces configured on node %u\n",
1927 ctdb->cmd_pnn);
1928 return 0;
1931 if (options.machinereadable) {
1932 printf("%s%s%s%s%s%s%s\n", options.sep,
1933 "Name", options.sep,
1934 "LinkStatus", options.sep,
1935 "References", options.sep);
1936 } else {
1937 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1940 for (i=0; i<ifaces->num; i++) {
1941 if (options.machinereadable) {
1942 printf("%s%s%s%u%s%u%s\n", options.sep,
1943 ifaces->iface[i].name, options.sep,
1944 ifaces->iface[i].link_state, options.sep,
1945 ifaces->iface[i].references, options.sep);
1946 } else {
1947 printf("name:%s link:%s references:%u\n",
1948 ifaces->iface[i].name,
1949 ifaces->iface[i].link_state ? "up" : "down",
1950 ifaces->iface[i].references);
1954 return 0;
1957 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1958 int argc, const char **argv)
1960 struct ctdb_iface_list *ifaces;
1961 struct ctdb_iface *iface;
1962 unsigned int i;
1963 int ret;
1965 if (argc != 2) {
1966 usage("setifacelink");
1969 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1970 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1971 return 1;
1974 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1975 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1976 if (ret != 0) {
1977 fprintf(stderr,
1978 "Failed to get interface information from node %u\n",
1979 ctdb->cmd_pnn);
1980 return ret;
1983 iface = NULL;
1984 for (i=0; i<ifaces->num; i++) {
1985 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1986 iface = &ifaces->iface[i];
1987 break;
1991 if (iface == NULL) {
1992 printf("Interface %s not configured on node %u\n",
1993 argv[0], ctdb->cmd_pnn);
1994 return 1;
1997 if (strcmp(argv[1], "up") == 0) {
1998 iface->link_state = 1;
1999 } else if (strcmp(argv[1], "down") == 0) {
2000 iface->link_state = 0;
2001 } else {
2002 usage("setifacelink");
2003 return 1;
2006 iface->references = 0;
2008 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
2009 ctdb->cmd_pnn, TIMEOUT(), iface);
2010 if (ret != 0) {
2011 return ret;
2014 return 0;
2017 static int control_process_exists(TALLOC_CTX *mem_ctx,
2018 struct ctdb_context *ctdb,
2019 int argc, const char **argv)
2021 pid_t pid;
2022 uint64_t srvid = 0;
2023 int status;
2024 int ret = 0;
2026 if (argc != 1 && argc != 2) {
2027 usage("process-exists");
2030 pid = atoi(argv[0]);
2031 if (argc == 2) {
2032 srvid = smb_strtoull(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
2033 if (ret != 0) {
2034 return ret;
2038 if (srvid == 0) {
2039 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
2040 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
2041 } else {
2042 struct ctdb_pid_srvid pid_srvid;
2044 pid_srvid.pid = pid;
2045 pid_srvid.srvid = srvid;
2047 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
2048 ctdb->client, ctdb->cmd_pnn,
2049 TIMEOUT(), &pid_srvid,
2050 &status);
2053 if (ret != 0) {
2054 return ret;
2057 if (srvid == 0) {
2058 printf("PID %d %s\n", pid,
2059 (status == 0 ? "exists" : "does not exist"));
2060 } else {
2061 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
2062 (status == 0 ? "exists" : "does not exist"));
2064 return status;
2067 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2068 int argc, const char **argv)
2070 struct ctdb_dbid_map *dbmap;
2071 unsigned int i;
2072 int ret;
2074 if (argc != 0) {
2075 usage("getdbmap");
2078 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
2079 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
2080 if (ret != 0) {
2081 return ret;
2084 if (options.machinereadable == 1) {
2085 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
2086 options.sep,
2087 "ID", options.sep,
2088 "Name", options.sep,
2089 "Path", options.sep,
2090 "Persistent", options.sep,
2091 "Sticky", options.sep,
2092 "Unhealthy", options.sep,
2093 "Readonly", options.sep,
2094 "Replicated", options.sep);
2095 } else {
2096 printf("Number of databases:%d\n", dbmap->num);
2099 for (i=0; i<dbmap->num; i++) {
2100 const char *name;
2101 const char *path;
2102 const char *health;
2103 bool persistent;
2104 bool readonly;
2105 bool sticky;
2106 bool replicated;
2107 uint32_t db_id;
2109 db_id = dbmap->dbs[i].db_id;
2111 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
2112 ctdb->cmd_pnn, TIMEOUT(), db_id,
2113 &name);
2114 if (ret != 0) {
2115 return ret;
2118 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2119 ctdb->cmd_pnn, TIMEOUT(), db_id,
2120 &path);
2121 if (ret != 0) {
2122 return ret;
2125 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2126 ctdb->cmd_pnn, TIMEOUT(), db_id,
2127 &health);
2128 if (ret != 0) {
2129 return ret;
2132 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
2133 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
2134 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
2135 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
2137 if (options.machinereadable == 1) {
2138 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2139 options.sep,
2140 db_id, options.sep,
2141 name, options.sep,
2142 path, options.sep,
2143 !! (persistent), options.sep,
2144 !! (sticky), options.sep,
2145 !! (health), options.sep,
2146 !! (readonly), options.sep,
2147 !! (replicated), options.sep);
2148 } else {
2149 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2150 db_id, name, path,
2151 persistent ? " PERSISTENT" : "",
2152 sticky ? " STICKY" : "",
2153 readonly ? " READONLY" : "",
2154 replicated ? " REPLICATED" : "",
2155 health ? " UNHEALTHY" : "");
2158 talloc_free(discard_const(name));
2159 talloc_free(discard_const(path));
2160 talloc_free(discard_const(health));
2163 return 0;
2166 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2167 int argc, const char **argv)
2169 uint32_t db_id;
2170 const char *db_name, *db_path, *db_health;
2171 uint8_t db_flags;
2172 int ret;
2174 if (argc != 1) {
2175 usage("getdbstatus");
2178 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2179 return 1;
2182 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2183 ctdb->cmd_pnn, TIMEOUT(), db_id,
2184 &db_path);
2185 if (ret != 0) {
2186 return ret;
2189 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2190 ctdb->cmd_pnn, TIMEOUT(), db_id,
2191 &db_health);
2192 if (ret != 0) {
2193 return ret;
2196 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2197 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2198 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2199 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2200 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2201 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2202 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2203 return 0;
2206 struct dump_record_state {
2207 uint32_t count;
2210 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2212 static void dump_tdb_data(const char *name, TDB_DATA val)
2214 size_t i;
2216 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2217 for (i=0; i<val.dsize; i++) {
2218 if (ISASCII(val.dptr[i])) {
2219 fprintf(stdout, "%c", val.dptr[i]);
2220 } else {
2221 fprintf(stdout, "\\%02X", val.dptr[i]);
2224 fprintf(stdout, "\"\n");
2227 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2229 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2230 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2231 fprintf(stdout, "flags: 0x%08x", header->flags);
2232 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2233 fprintf(stdout, " MIGRATED_WITH_DATA");
2235 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2236 fprintf(stdout, " VACUUM_MIGRATED");
2238 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2239 fprintf(stdout, " AUTOMATIC");
2241 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2242 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2244 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2245 fprintf(stdout, " RO_HAVE_READONLY");
2247 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2248 fprintf(stdout, " RO_REVOKING_READONLY");
2250 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2251 fprintf(stdout, " RO_REVOKE_COMPLETE");
2253 fprintf(stdout, "\n");
2257 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2258 TDB_DATA key, TDB_DATA data, void *private_data)
2260 struct dump_record_state *state =
2261 (struct dump_record_state *)private_data;
2263 state->count += 1;
2265 dump_tdb_data("key", key);
2266 dump_ltdb_header(header);
2267 dump_tdb_data("data", data);
2268 fprintf(stdout, "\n");
2270 return 0;
2273 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2274 int argc, const char **argv)
2276 struct ctdb_db_context *db;
2277 const char *db_name;
2278 uint32_t db_id;
2279 uint8_t db_flags;
2280 struct dump_record_state state;
2281 int ret;
2283 if (argc != 1) {
2284 usage("catdb");
2287 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2288 return 1;
2291 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2292 db_flags, &db);
2293 if (ret != 0) {
2294 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2295 return ret;
2298 state.count = 0;
2300 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2301 ctdb->cmd_pnn, TIMEOUT(),
2302 dump_record, &state);
2304 printf("Dumped %u records\n", state.count);
2306 return ret;
2309 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2310 int argc, const char **argv)
2312 struct ctdb_db_context *db;
2313 const char *db_name;
2314 uint32_t db_id;
2315 uint8_t db_flags;
2316 struct dump_record_state state;
2317 int ret;
2319 if (argc != 1) {
2320 usage("cattdb");
2323 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2324 return 1;
2327 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2328 db_flags, &db);
2329 if (ret != 0) {
2330 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2331 return ret;
2334 state.count = 0;
2335 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2337 printf("Dumped %u record(s)\n", state.count);
2339 return ret;
2342 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2343 struct ctdb_context *ctdb,
2344 int argc, const char **argv)
2346 uint32_t caps;
2347 int ret;
2349 if (argc != 0) {
2350 usage("getcapabilities");
2353 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2354 ctdb->cmd_pnn, TIMEOUT(), &caps);
2355 if (ret != 0) {
2356 return ret;
2359 if (options.machinereadable == 1) {
2360 printf("%s%s%s%s%s\n",
2361 options.sep,
2362 "LEADER", options.sep,
2363 "LMASTER", options.sep);
2364 printf("%s%d%s%d%s\n", options.sep,
2365 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2366 !! (caps & CTDB_CAP_LMASTER), options.sep);
2367 } else {
2368 printf("LEADER: %s\n",
2369 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2370 printf("LMASTER: %s\n",
2371 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2374 return 0;
2377 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2378 int argc, const char **argv)
2380 printf("%u\n", ctdb_client_pnn(ctdb->client));
2381 return 0;
2384 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2385 int argc, const char **argv)
2387 char *t, *lvs_helper = NULL;
2389 if (argc != 1) {
2390 usage("lvs");
2393 t = getenv("CTDB_LVS_HELPER");
2394 if (t != NULL) {
2395 lvs_helper = talloc_strdup(mem_ctx, t);
2396 } else {
2397 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2398 CTDB_HELPER_BINDIR);
2401 if (lvs_helper == NULL) {
2402 fprintf(stderr, "Unable to set LVS helper\n");
2403 return 1;
2406 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2409 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2410 int argc, const char **argv)
2412 int log_level;
2413 int ret;
2414 bool found;
2416 if (argc != 1) {
2417 usage("setdebug");
2420 found = debug_level_parse(argv[0], &log_level);
2421 if (! found) {
2422 fprintf(stderr,
2423 "Invalid debug level '%s'. Valid levels are:\n",
2424 argv[0]);
2425 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2426 return 1;
2429 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2430 ctdb->cmd_pnn, TIMEOUT(), log_level);
2431 if (ret != 0) {
2432 return ret;
2435 return 0;
2438 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2439 int argc, const char **argv)
2441 int loglevel;
2442 const char *log_str;
2443 int ret;
2445 if (argc != 0) {
2446 usage("getdebug");
2449 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2450 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2451 if (ret != 0) {
2452 return ret;
2455 log_str = debug_level_to_string(loglevel);
2456 printf("%s\n", log_str);
2458 return 0;
2461 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2462 int argc, const char **argv)
2464 const char *db_name;
2465 uint8_t db_flags = 0;
2466 int ret;
2468 if (argc < 1 || argc > 2) {
2469 usage("attach");
2472 db_name = argv[0];
2473 if (argc == 2) {
2474 if (strcmp(argv[1], "persistent") == 0) {
2475 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2476 } else if (strcmp(argv[1], "readonly") == 0) {
2477 db_flags = CTDB_DB_FLAGS_READONLY;
2478 } else if (strcmp(argv[1], "sticky") == 0) {
2479 db_flags = CTDB_DB_FLAGS_STICKY;
2480 } else if (strcmp(argv[1], "replicated") == 0) {
2481 db_flags = CTDB_DB_FLAGS_REPLICATED;
2482 } else {
2483 usage("attach");
2487 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2488 db_flags, NULL);
2489 if (ret != 0) {
2490 return ret;
2493 return 0;
2496 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2497 int argc, const char **argv)
2499 const char *db_name;
2500 uint32_t db_id;
2501 uint8_t db_flags;
2502 struct ctdb_node_map *nodemap;
2503 int recmode;
2504 unsigned int j;
2505 int ret, ret2, i;
2507 if (argc < 1) {
2508 usage("detach");
2511 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2512 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2513 if (ret != 0) {
2514 return ret;
2517 if (recmode == CTDB_RECOVERY_ACTIVE) {
2518 fprintf(stderr, "Database cannot be detached"
2519 " when recovery is active\n");
2520 return 1;
2523 nodemap = get_nodemap(ctdb, false);
2524 if (nodemap == NULL) {
2525 return 1;
2528 for (j=0; j<nodemap->num; j++) {
2529 uint32_t value;
2531 if (nodemap->node[j].flags & NODE_FLAGS_DISCONNECTED) {
2532 continue;
2534 if (nodemap->node[j].flags & NODE_FLAGS_DELETED) {
2535 continue;
2537 if (nodemap->node[j].flags & NODE_FLAGS_INACTIVE) {
2538 fprintf(stderr, "Database cannot be detached on"
2539 " inactive (stopped or banned) node %u\n",
2540 nodemap->node[j].pnn);
2541 return 1;
2544 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2545 nodemap->node[j].pnn, TIMEOUT(),
2546 "AllowClientDBAttach", &value);
2547 if (ret != 0) {
2548 fprintf(stderr,
2549 "Unable to get tunable AllowClientDBAttach"
2550 " from node %u\n", nodemap->node[j].pnn);
2551 return ret;
2554 if (value == 1) {
2555 fprintf(stderr,
2556 "Database access is still active on node %u."
2557 " Set AllowclientDBAttach=0 on all nodes.\n",
2558 nodemap->node[j].pnn);
2559 return 1;
2563 ret2 = 0;
2564 for (i=0; i<argc; i++) {
2565 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2566 &db_flags)) {
2567 continue;
2570 if (db_flags &
2571 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2572 fprintf(stderr,
2573 "Only volatile databases can be detached\n");
2574 return 1;
2577 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2578 if (ret != 0) {
2579 fprintf(stderr, "Database %s detach failed\n", db_name);
2580 ret2 = ret;
2584 return ret2;
2587 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2588 int argc, const char **argv)
2590 const char *mem_str;
2591 ssize_t n;
2592 int ret;
2594 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2595 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2596 if (ret != 0) {
2597 return ret;
2600 n = write(1, mem_str, strlen(mem_str));
2601 if (n < 0 || (size_t)n != strlen(mem_str)) {
2602 fprintf(stderr, "Failed to write talloc summary\n");
2603 return 1;
2606 return 0;
2609 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2611 bool *done = (bool *)private_data;
2612 size_t len;
2613 ssize_t n;
2615 len = strnlen((const char *)data.dptr, data.dsize);
2616 n = write(1, data.dptr, len);
2617 if (n < 0 || (size_t)n != len) {
2618 fprintf(stderr, "Failed to write talloc summary\n");
2621 *done = true;
2624 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2625 int argc, const char **argv)
2627 struct ctdb_srvid_message msg = { 0 };
2628 int ret;
2629 bool done = false;
2631 msg.pnn = ctdb->pnn;
2632 msg.srvid = next_srvid(ctdb);
2634 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2635 msg.srvid, dump_memory, &done);
2636 if (ret != 0) {
2637 return ret;
2640 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2641 ctdb->cmd_pnn, &msg);
2642 if (ret != 0) {
2643 return ret;
2646 ctdb_client_wait(ctdb->ev, &done);
2647 return 0;
2650 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2651 int argc, const char **argv)
2653 pid_t pid;
2654 int ret;
2656 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2657 ctdb->cmd_pnn, TIMEOUT(), &pid);
2658 if (ret != 0) {
2659 return ret;
2662 printf("%u\n", pid);
2663 return 0;
2666 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2667 const char *desc, uint32_t flag, bool set_flag)
2669 struct ctdb_node_map *nodemap;
2670 bool flag_is_set;
2672 nodemap = get_nodemap(ctdb, false);
2673 if (nodemap == NULL) {
2674 return 1;
2677 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2678 if (set_flag == flag_is_set) {
2679 if (set_flag) {
2680 fprintf(stderr, "Node %u is already %s\n",
2681 ctdb->cmd_pnn, desc);
2682 } else {
2683 fprintf(stderr, "Node %u is not %s\n",
2684 ctdb->cmd_pnn, desc);
2686 return 0;
2689 return 1;
2692 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2693 uint32_t flag, bool set_flag)
2695 struct ctdb_node_map *nodemap;
2696 bool flag_is_set;
2698 while (1) {
2699 nodemap = get_nodemap(ctdb, true);
2700 if (nodemap == NULL) {
2701 fprintf(stderr,
2702 "Failed to get nodemap, trying again\n");
2703 sleep(1);
2704 continue;
2707 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2708 if (flag_is_set == set_flag) {
2709 break;
2712 sleep(1);
2716 struct ipreallocate_state {
2717 int status;
2718 bool done;
2721 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2722 void *private_data)
2724 struct ipreallocate_state *state =
2725 (struct ipreallocate_state *)private_data;
2727 if (data.dsize != sizeof(int)) {
2728 /* Ignore packet */
2729 return;
2732 state->status = *(int *)data.dptr;
2733 state->done = true;
2736 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2738 struct ctdb_srvid_message msg = { 0 };
2739 struct ipreallocate_state state;
2740 int ret;
2742 msg.pnn = ctdb->pnn;
2743 msg.srvid = next_srvid(ctdb);
2745 state.done = false;
2746 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2747 msg.srvid,
2748 ipreallocate_handler, &state);
2749 if (ret != 0) {
2750 return ret;
2753 while (true) {
2754 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2755 ctdb->client,
2756 CTDB_BROADCAST_CONNECTED,
2757 &msg);
2758 if (ret != 0) {
2759 goto fail;
2762 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2763 TIMEOUT());
2764 if (ret != 0) {
2765 continue;
2768 if (state.status >= 0) {
2769 ret = 0;
2770 } else {
2771 ret = state.status;
2773 break;
2776 fail:
2777 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2778 msg.srvid, &state);
2779 return ret;
2782 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2783 int argc, const char **argv)
2785 int ret;
2787 if (argc != 0) {
2788 usage("disable");
2791 ret = check_flags(mem_ctx, ctdb, "disabled",
2792 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2793 if (ret == 0) {
2794 return 0;
2797 ret = ctdb_ctrl_disable_node(mem_ctx,
2798 ctdb->ev,
2799 ctdb->client,
2800 ctdb->cmd_pnn,
2801 TIMEOUT());
2802 if (ret != 0) {
2803 fprintf(stderr, "Failed to disable node %u\n", ctdb->cmd_pnn);
2804 return ret;
2807 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2808 return ipreallocate(mem_ctx, ctdb);
2811 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2812 int argc, const char **argv)
2814 int ret;
2816 if (argc != 0) {
2817 usage("enable");
2820 ret = check_flags(mem_ctx, ctdb, "disabled",
2821 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2822 if (ret == 0) {
2823 return 0;
2826 ret = ctdb_ctrl_enable_node(mem_ctx,
2827 ctdb->ev,
2828 ctdb->client,
2829 ctdb->cmd_pnn,
2830 TIMEOUT());
2831 if (ret != 0) {
2832 fprintf(stderr, "Failed to enable node %u\n", ctdb->cmd_pnn);
2833 return ret;
2836 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2837 return ipreallocate(mem_ctx, ctdb);
2840 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2841 int argc, const char **argv)
2843 int ret;
2845 if (argc != 0) {
2846 usage("stop");
2849 ret = check_flags(mem_ctx, ctdb, "stopped",
2850 NODE_FLAGS_STOPPED, true);
2851 if (ret == 0) {
2852 return 0;
2855 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2856 ctdb->cmd_pnn, TIMEOUT());
2857 if (ret != 0) {
2858 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2859 return ret;
2862 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2863 return ipreallocate(mem_ctx, ctdb);
2866 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2867 int argc, const char **argv)
2869 int ret;
2871 if (argc != 0) {
2872 usage("continue");
2875 ret = check_flags(mem_ctx, ctdb, "stopped",
2876 NODE_FLAGS_STOPPED, false);
2877 if (ret == 0) {
2878 return 0;
2881 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2882 ctdb->cmd_pnn, TIMEOUT());
2883 if (ret != 0) {
2884 fprintf(stderr, "Failed to continue stopped node %u\n",
2885 ctdb->cmd_pnn);
2886 return ret;
2889 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2890 return ipreallocate(mem_ctx, ctdb);
2893 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2894 int argc, const char **argv)
2896 struct ctdb_ban_state ban_state;
2897 int ret = 0;
2899 if (argc != 1) {
2900 usage("ban");
2903 ret = check_flags(mem_ctx, ctdb, "banned",
2904 NODE_FLAGS_BANNED, true);
2905 if (ret == 0) {
2906 return 0;
2909 ban_state.pnn = ctdb->cmd_pnn;
2910 ban_state.time = smb_strtoul(argv[0], NULL, 0, &ret, SMB_STR_STANDARD);
2911 if (ret != 0) {
2912 return ret;
2915 if (ban_state.time == 0) {
2916 fprintf(stderr, "Ban time cannot be zero\n");
2917 return EINVAL;
2920 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2921 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2922 if (ret != 0) {
2923 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2924 return ret;
2927 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2928 return ipreallocate(mem_ctx, ctdb);
2932 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2933 int argc, const char **argv)
2935 struct ctdb_ban_state ban_state;
2936 int ret;
2938 if (argc != 0) {
2939 usage("unban");
2942 ret = check_flags(mem_ctx, ctdb, "banned",
2943 NODE_FLAGS_BANNED, false);
2944 if (ret == 0) {
2945 return 0;
2948 ban_state.pnn = ctdb->cmd_pnn;
2949 ban_state.time = 0;
2951 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2952 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2953 if (ret != 0) {
2954 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2955 return ret;
2958 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2959 return ipreallocate(mem_ctx, ctdb);
2963 static void wait_for_shutdown(void *private_data)
2965 bool *done = (bool *)private_data;
2967 *done = true;
2970 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2971 int argc, const char **argv)
2973 int ret;
2974 bool done = false;
2976 if (argc != 0) {
2977 usage("shutdown");
2980 if (ctdb->pnn == ctdb->cmd_pnn) {
2981 ctdb_client_set_disconnect_callback(ctdb->client,
2982 wait_for_shutdown,
2983 &done);
2986 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2987 ctdb->cmd_pnn, TIMEOUT());
2988 if (ret != 0) {
2989 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2990 return ret;
2993 if (ctdb->pnn == ctdb->cmd_pnn) {
2994 ctdb_client_wait(ctdb->ev, &done);
2997 return 0;
3000 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3001 uint32_t *generation)
3003 uint32_t leader;
3004 int recmode;
3005 struct ctdb_vnn_map *vnnmap;
3006 int ret;
3008 again:
3009 ret = get_leader(mem_ctx, ctdb, &leader);
3010 if (ret != 0) {
3011 fprintf(stderr, "Failed to find leader\n");
3012 return ret;
3015 ret = ctdb_ctrl_get_recmode(mem_ctx,
3016 ctdb->ev,
3017 ctdb->client,
3018 leader,
3019 TIMEOUT(),
3020 &recmode);
3021 if (ret != 0) {
3022 fprintf(stderr,
3023 "Failed to get recovery mode from node %u\n",
3024 leader);
3025 return ret;
3028 if (recmode == CTDB_RECOVERY_ACTIVE) {
3029 sleep(1);
3030 goto again;
3033 ret = ctdb_ctrl_getvnnmap(mem_ctx,
3034 ctdb->ev,
3035 ctdb->client,
3036 leader,
3037 TIMEOUT(),
3038 &vnnmap);
3039 if (ret != 0) {
3040 fprintf(stderr,
3041 "Failed to get generation from node %u\n",
3042 leader);
3043 return ret;
3046 if (vnnmap->generation == INVALID_GENERATION) {
3047 talloc_free(vnnmap);
3048 sleep(1);
3049 goto again;
3052 *generation = vnnmap->generation;
3053 talloc_free(vnnmap);
3054 return 0;
3058 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3059 int argc, const char **argv)
3061 uint32_t generation, next_generation;
3062 int ret;
3064 if (argc != 0) {
3065 usage("recover");
3068 ret = get_generation(mem_ctx, ctdb, &generation);
3069 if (ret != 0) {
3070 return ret;
3073 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
3074 ctdb->cmd_pnn, TIMEOUT(),
3075 CTDB_RECOVERY_ACTIVE);
3076 if (ret != 0) {
3077 fprintf(stderr, "Failed to set recovery mode active\n");
3078 return ret;
3081 while (1) {
3082 ret = get_generation(mem_ctx, ctdb, &next_generation);
3083 if (ret != 0) {
3084 fprintf(stderr,
3085 "Failed to confirm end of recovery\n");
3086 return ret;
3089 if (next_generation != generation) {
3090 break;
3093 sleep (1);
3096 return 0;
3099 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3100 int argc, const char **argv)
3102 if (argc != 0) {
3103 usage("ipreallocate");
3106 return ipreallocate(mem_ctx, ctdb);
3109 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3110 int argc, const char **argv)
3112 struct ctdb_addr_info addr_info;
3113 int ret;
3115 if (argc != 2) {
3116 usage("gratarp");
3119 ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
3120 if (ret != 0) {
3121 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3122 return 1;
3124 addr_info.iface = argv[1];
3126 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3127 ctdb->cmd_pnn, TIMEOUT(),
3128 &addr_info);
3129 if (ret != 0) {
3130 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3131 ctdb->cmd_pnn);
3132 return ret;
3135 return 0;
3138 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3139 int argc, const char **argv)
3141 ctdb_sock_addr src, dst;
3142 int ret;
3144 if (argc != 0 && argc != 2) {
3145 usage("tickle");
3148 if (argc == 0) {
3149 struct ctdb_connection_list *clist;
3150 unsigned int i;
3151 unsigned int num_failed;
3153 /* Client first but the src/dst logic is confused */
3154 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3155 if (ret != 0) {
3156 return ret;
3159 num_failed = 0;
3160 for (i = 0; i < clist->num; i++) {
3161 ret = ctdb_sys_send_tcp(&clist->conn[i].src,
3162 &clist->conn[i].dst,
3163 0, 0, 0);
3164 if (ret != 0) {
3165 num_failed += 1;
3169 TALLOC_FREE(clist);
3171 if (num_failed > 0) {
3172 fprintf(stderr, "Failed to send %d tickles\n",
3173 num_failed);
3174 return 1;
3177 return 0;
3181 ret = ctdb_sock_addr_from_string(argv[0], &src, true);
3182 if (ret != 0) {
3183 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3184 return 1;
3187 ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
3188 if (ret != 0) {
3189 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3190 return 1;
3193 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3194 if (ret != 0) {
3195 fprintf(stderr, "Failed to send tickle ack\n");
3196 return ret;
3199 return 0;
3202 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3203 int argc, const char **argv)
3205 ctdb_sock_addr addr;
3206 struct ctdb_tickle_list *tickles;
3207 unsigned port = 0;
3208 unsigned int i;
3209 int ret = 0;
3211 if (argc < 1 || argc > 2) {
3212 usage("gettickles");
3215 if (argc == 2) {
3216 port = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3217 if (ret != 0) {
3218 return ret;
3222 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3223 if (ret != 0) {
3224 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3225 return 1;
3227 ctdb_sock_addr_set_port(&addr, port);
3229 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3230 ctdb->cmd_pnn, TIMEOUT(), &addr,
3231 &tickles);
3232 if (ret != 0) {
3233 fprintf(stderr, "Failed to get list of connections\n");
3234 return ret;
3237 if (options.machinereadable) {
3238 printf("%s%s%s%s%s%s%s%s%s\n",
3239 options.sep,
3240 "Source IP", options.sep,
3241 "Port", options.sep,
3242 "Destination IP", options.sep,
3243 "Port", options.sep);
3244 for (i=0; i<tickles->num; i++) {
3245 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3246 ctdb_sock_addr_to_string(
3247 mem_ctx, &tickles->conn[i].src, false),
3248 options.sep,
3249 ntohs(tickles->conn[i].src.ip.sin_port),
3250 options.sep,
3251 ctdb_sock_addr_to_string(
3252 mem_ctx, &tickles->conn[i].dst, false),
3253 options.sep,
3254 ntohs(tickles->conn[i].dst.ip.sin_port),
3255 options.sep);
3257 } else {
3258 printf("Connections for IP: %s\n",
3259 ctdb_sock_addr_to_string(mem_ctx,
3260 &tickles->addr, false));
3261 printf("Num connections: %u\n", tickles->num);
3262 for (i=0; i<tickles->num; i++) {
3263 printf("SRC: %s DST: %s\n",
3264 ctdb_sock_addr_to_string(
3265 mem_ctx, &tickles->conn[i].src, true),
3266 ctdb_sock_addr_to_string(
3267 mem_ctx, &tickles->conn[i].dst, true));
3271 talloc_free(tickles);
3272 return 0;
3275 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3276 struct ctdb_connection *conn);
3278 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3280 struct process_clist_state {
3281 struct ctdb_connection_list *clist;
3282 int count;
3283 unsigned int num_failed, num_total;
3284 clist_reply_func reply_func;
3287 static void process_clist_done(struct tevent_req *subreq);
3289 static struct tevent_req *process_clist_send(
3290 TALLOC_CTX *mem_ctx,
3291 struct ctdb_context *ctdb,
3292 struct ctdb_connection_list *clist,
3293 clist_request_func request_func,
3294 clist_reply_func reply_func)
3296 struct tevent_req *req, *subreq;
3297 struct process_clist_state *state;
3298 struct ctdb_req_control request;
3299 unsigned int i;
3301 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3302 if (req == NULL) {
3303 return NULL;
3306 state->clist = clist;
3307 state->reply_func = reply_func;
3309 for (i = 0; i < clist->num; i++) {
3310 request_func(&request, &clist->conn[i]);
3311 subreq = ctdb_client_control_send(state, ctdb->ev,
3312 ctdb->client, ctdb->cmd_pnn,
3313 TIMEOUT(), &request);
3314 if (tevent_req_nomem(subreq, req)) {
3315 return tevent_req_post(req, ctdb->ev);
3317 tevent_req_set_callback(subreq, process_clist_done, req);
3320 return req;
3323 static void process_clist_done(struct tevent_req *subreq)
3325 struct tevent_req *req = tevent_req_callback_data(
3326 subreq, struct tevent_req);
3327 struct process_clist_state *state = tevent_req_data(
3328 req, struct process_clist_state);
3329 struct ctdb_reply_control *reply;
3330 int ret;
3331 bool status;
3333 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3334 TALLOC_FREE(subreq);
3335 if (! status) {
3336 state->num_failed += 1;
3337 goto done;
3340 ret = state->reply_func(reply);
3341 if (ret != 0) {
3342 state->num_failed += 1;
3343 goto done;
3346 done:
3347 state->num_total += 1;
3348 if (state->num_total == state->clist->num) {
3349 tevent_req_done(req);
3353 static int process_clist_recv(struct tevent_req *req)
3355 struct process_clist_state *state = tevent_req_data(
3356 req, struct process_clist_state);
3358 return state->num_failed;
3361 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3362 int argc, const char **argv)
3364 struct ctdb_connection conn;
3365 int ret;
3367 if (argc != 0 && argc != 2) {
3368 usage("addtickle");
3371 if (argc == 0) {
3372 struct ctdb_connection_list *clist;
3373 struct tevent_req *req;
3375 /* Client first but the src/dst logic is confused */
3376 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3377 if (ret != 0) {
3378 return ret;
3380 if (clist->num == 0) {
3381 return 0;
3384 req = process_clist_send(mem_ctx, ctdb, clist,
3385 ctdb_req_control_tcp_add_delayed_update,
3386 ctdb_reply_control_tcp_add_delayed_update);
3387 if (req == NULL) {
3388 talloc_free(clist);
3389 return ENOMEM;
3392 tevent_req_poll(req, ctdb->ev);
3393 talloc_free(clist);
3395 ret = process_clist_recv(req);
3396 if (ret != 0) {
3397 fprintf(stderr, "Failed to add %d tickles\n", ret);
3398 return 1;
3401 return 0;
3404 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3405 if (ret != 0) {
3406 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3407 return 1;
3409 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3410 if (ret != 0) {
3411 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3412 return 1;
3415 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3416 ctdb->client, ctdb->cmd_pnn,
3417 TIMEOUT(), &conn);
3418 if (ret != 0) {
3419 fprintf(stderr, "Failed to register connection\n");
3420 return ret;
3423 return 0;
3426 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3427 int argc, const char **argv)
3429 struct ctdb_connection conn;
3430 int ret;
3432 if (argc != 0 && argc != 2) {
3433 usage("deltickle");
3436 if (argc == 0) {
3437 struct ctdb_connection_list *clist;
3438 struct tevent_req *req;
3440 /* Client first but the src/dst logic is confused */
3441 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3442 if (ret != 0) {
3443 return ret;
3445 if (clist->num == 0) {
3446 return 0;
3449 req = process_clist_send(mem_ctx, ctdb, clist,
3450 ctdb_req_control_tcp_remove,
3451 ctdb_reply_control_tcp_remove);
3452 if (req == NULL) {
3453 talloc_free(clist);
3454 return ENOMEM;
3457 tevent_req_poll(req, ctdb->ev);
3458 talloc_free(clist);
3460 ret = process_clist_recv(req);
3461 if (ret != 0) {
3462 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3463 return 1;
3466 return 0;
3469 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3470 if (ret != 0) {
3471 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3472 return 1;
3474 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3475 if (ret != 0) {
3476 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3477 return 1;
3480 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3481 ctdb->cmd_pnn, TIMEOUT(), &conn);
3482 if (ret != 0) {
3483 fprintf(stderr, "Failed to unregister connection\n");
3484 return ret;
3487 return 0;
3490 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3491 int argc, const char **argv)
3493 struct ctdb_node_map *nodemap;
3494 unsigned int i;
3496 if (argc != 0) {
3497 usage("listnodes");
3500 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3501 if (nodemap == NULL) {
3502 return 1;
3505 for (i=0; i<nodemap->num; i++) {
3506 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3507 continue;
3510 if (options.machinereadable) {
3511 printf("%s%u%s%s%s\n", options.sep,
3512 nodemap->node[i].pnn, options.sep,
3513 ctdb_sock_addr_to_string(
3514 mem_ctx, &nodemap->node[i].addr, false),
3515 options.sep);
3516 } else {
3517 printf("%s\n",
3518 ctdb_sock_addr_to_string(
3519 mem_ctx, &nodemap->node[i].addr, false));
3523 return 0;
3526 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3527 struct ctdb_node_map *nodemap2)
3529 unsigned int i;
3531 if (nodemap1->num != nodemap2->num) {
3532 return false;
3535 for (i=0; i<nodemap1->num; i++) {
3536 struct ctdb_node_and_flags *n1, *n2;
3538 n1 = &nodemap1->node[i];
3539 n2 = &nodemap2->node[i];
3541 if ((n1->pnn != n2->pnn) ||
3542 (n1->flags != n2->flags) ||
3543 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3544 return false;
3548 return true;
3551 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3552 struct ctdb_node_map *nm,
3553 struct ctdb_node_map *fnm,
3554 bool *reload)
3556 unsigned int i;
3557 bool check_failed = false;
3559 *reload = false;
3561 for (i=0; i<nm->num; i++) {
3562 if (i >= fnm->num) {
3563 fprintf(stderr,
3564 "Node %u (%s) missing from nodes file\n",
3565 nm->node[i].pnn,
3566 ctdb_sock_addr_to_string(
3567 mem_ctx, &nm->node[i].addr, false));
3568 check_failed = true;
3569 continue;
3571 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3572 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3573 /* Node remains deleted */
3574 continue;
3577 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3578 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3579 /* Node not newly nor previously deleted */
3580 if (! ctdb_same_ip(&nm->node[i].addr,
3581 &fnm->node[i].addr)) {
3582 fprintf(stderr,
3583 "Node %u has changed IP address"
3584 " (was %s, now %s)\n",
3585 nm->node[i].pnn,
3586 ctdb_sock_addr_to_string(
3587 mem_ctx,
3588 &nm->node[i].addr, false),
3589 ctdb_sock_addr_to_string(
3590 mem_ctx,
3591 &fnm->node[i].addr, false));
3592 check_failed = true;
3593 } else {
3594 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3595 fprintf(stderr,
3596 "WARNING: Node %u is disconnected."
3597 " You MUST fix this node manually!\n",
3598 nm->node[i].pnn);
3601 continue;
3604 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3605 /* Node is being deleted */
3606 printf("Node %u is DELETED\n", nm->node[i].pnn);
3607 *reload = true;
3608 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3609 fprintf(stderr,
3610 "ERROR: Node %u is still connected\n",
3611 nm->node[i].pnn);
3612 check_failed = true;
3614 continue;
3617 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3618 /* Node was previously deleted */
3619 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3620 *reload = true;
3624 if (check_failed) {
3625 fprintf(stderr,
3626 "ERROR: Nodes will not be reloaded due to previous error\n");
3627 return 1;
3630 /* Leftover nodes in file are NEW */
3631 for (; i < fnm->num; i++) {
3632 printf("Node %u is NEW\n", fnm->node[i].pnn);
3633 *reload = true;
3636 return 0;
3639 struct disable_recoveries_state {
3640 uint32_t *pnn_list;
3641 unsigned int node_count;
3642 bool *reply;
3643 int status;
3644 bool done;
3647 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3648 void *private_data)
3650 struct disable_recoveries_state *state =
3651 (struct disable_recoveries_state *)private_data;
3652 unsigned int i;
3653 int ret;
3655 if (data.dsize != sizeof(int)) {
3656 /* Ignore packet */
3657 return;
3660 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3661 ret = *(int *)data.dptr;
3662 if (ret < 0) {
3663 state->status = ret;
3664 state->done = true;
3665 return;
3667 for (i=0; i<state->node_count; i++) {
3668 if (state->pnn_list[i] == (uint32_t)ret) {
3669 state->reply[i] = true;
3670 break;
3674 state->done = true;
3675 for (i=0; i<state->node_count; i++) {
3676 if (! state->reply[i]) {
3677 state->done = false;
3678 break;
3683 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3684 uint32_t timeout, uint32_t *pnn_list, int count)
3686 struct ctdb_disable_message disable = { 0 };
3687 struct disable_recoveries_state state;
3688 int ret, i;
3690 disable.pnn = ctdb->pnn;
3691 disable.srvid = next_srvid(ctdb);
3692 disable.timeout = timeout;
3694 state.pnn_list = pnn_list;
3695 state.node_count = count;
3696 state.done = false;
3697 state.status = 0;
3698 state.reply = talloc_zero_array(mem_ctx, bool, count);
3699 if (state.reply == NULL) {
3700 return ENOMEM;
3703 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3704 disable.srvid,
3705 disable_recoveries_handler,
3706 &state);
3707 if (ret != 0) {
3708 return ret;
3711 for (i=0; i<count; i++) {
3712 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3713 ctdb->client,
3714 pnn_list[i],
3715 &disable);
3716 if (ret != 0) {
3717 goto fail;
3721 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3722 if (ret == ETIME) {
3723 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3724 } else {
3725 ret = (state.status >= 0 ? 0 : 1);
3728 fail:
3729 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3730 disable.srvid, &state);
3731 return ret;
3734 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3735 int argc, const char **argv)
3737 struct ctdb_node_map *nodemap = NULL;
3738 struct ctdb_node_map *file_nodemap;
3739 struct ctdb_node_map *remote_nodemap;
3740 struct ctdb_req_control request;
3741 struct ctdb_reply_control **reply;
3742 bool reload;
3743 unsigned int i;
3744 int count;
3745 int ret;
3746 uint32_t *pnn_list;
3748 nodemap = get_nodemap(ctdb, false);
3749 if (nodemap == NULL) {
3750 return 1;
3753 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3754 if (file_nodemap == NULL) {
3755 return 1;
3758 for (i=0; i<nodemap->num; i++) {
3759 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3760 continue;
3763 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3764 nodemap->node[i].pnn, TIMEOUT(),
3765 &remote_nodemap);
3766 if (ret != 0) {
3767 fprintf(stderr,
3768 "ERROR: Failed to get nodes file from node %u\n",
3769 nodemap->node[i].pnn);
3770 return ret;
3773 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3774 fprintf(stderr,
3775 "ERROR: Nodes file on node %u differs"
3776 " from current node (%u)\n",
3777 nodemap->node[i].pnn, ctdb->pnn);
3778 return 1;
3782 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3783 if (ret != 0) {
3784 return ret;
3787 if (! reload) {
3788 fprintf(stderr, "No change in nodes file,"
3789 " skipping unnecessary reload\n");
3790 return 0;
3793 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3794 mem_ctx, &pnn_list);
3795 if (count <= 0) {
3796 fprintf(stderr, "Memory allocation error\n");
3797 return 1;
3800 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3801 pnn_list, count);
3802 if (ret != 0) {
3803 fprintf(stderr, "Failed to disable recoveries\n");
3804 return ret;
3807 ctdb_req_control_reload_nodes_file(&request);
3808 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3809 pnn_list, count, TIMEOUT(),
3810 &request, NULL, &reply);
3811 if (ret != 0) {
3812 bool failed = false;
3813 int j;
3815 for (j=0; j<count; j++) {
3816 ret = ctdb_reply_control_reload_nodes_file(reply[j]);
3817 if (ret != 0) {
3818 fprintf(stderr,
3819 "Node %u failed to reload nodes\n",
3820 pnn_list[j]);
3821 failed = true;
3824 if (failed) {
3825 fprintf(stderr,
3826 "You MUST fix failed nodes manually!\n");
3830 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3831 if (ret != 0) {
3832 fprintf(stderr, "Failed to enable recoveries\n");
3833 return ret;
3836 return 0;
3839 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3840 ctdb_sock_addr *addr, uint32_t pnn)
3842 struct ctdb_public_ip_list *pubip_list;
3843 struct ctdb_public_ip pubip;
3844 struct ctdb_node_map *nodemap;
3845 struct ctdb_req_control request;
3846 uint32_t *pnn_list;
3847 unsigned int i;
3848 int ret, count;
3850 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3851 CTDB_BROADCAST_CONNECTED,
3852 2*options.timelimit);
3853 if (ret != 0) {
3854 fprintf(stderr, "Failed to disable IP check\n");
3855 return ret;
3858 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3859 pnn, TIMEOUT(), false, &pubip_list);
3860 if (ret != 0) {
3861 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3862 pnn);
3863 return ret;
3866 for (i=0; i<pubip_list->num; i++) {
3867 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3868 break;
3872 if (i == pubip_list->num) {
3873 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3874 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3875 return 1;
3878 nodemap = get_nodemap(ctdb, false);
3879 if (nodemap == NULL) {
3880 return 1;
3883 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3884 if (count <= 0) {
3885 fprintf(stderr, "Memory allocation error\n");
3886 return 1;
3889 pubip.pnn = pnn;
3890 pubip.addr = *addr;
3891 ctdb_req_control_release_ip(&request, &pubip);
3893 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3894 pnn_list, count, TIMEOUT(),
3895 &request, NULL, NULL);
3896 if (ret != 0) {
3897 fprintf(stderr, "Failed to release IP on nodes\n");
3898 return ret;
3901 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3902 pnn, TIMEOUT(), &pubip);
3903 if (ret != 0) {
3904 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3905 return ret;
3908 return 0;
3911 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3912 int argc, const char **argv)
3914 ctdb_sock_addr addr;
3915 uint32_t pnn;
3916 int retries = 0;
3917 int ret = 0;
3919 if (argc != 2) {
3920 usage("moveip");
3923 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3924 if (ret != 0) {
3925 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3926 return 1;
3929 pnn = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3930 if (pnn == CTDB_UNKNOWN_PNN || ret != 0) {
3931 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3932 return 1;
3935 while (retries < 5) {
3936 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3937 if (ret == 0) {
3938 break;
3941 sleep(3);
3942 retries++;
3945 if (ret != 0) {
3946 fprintf(stderr, "Failed to move IP %s to node %u\n",
3947 argv[0], pnn);
3948 return ret;
3951 return 0;
3954 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3955 uint32_t pnn)
3957 int ret;
3959 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3960 CTDB_BROADCAST_CONNECTED, pnn);
3961 if (ret != 0) {
3962 fprintf(stderr,
3963 "Failed to ask leader to distribute IPs\n");
3964 return ret;
3967 return 0;
3970 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3971 int argc, const char **argv)
3973 ctdb_sock_addr addr;
3974 struct ctdb_public_ip_list *pubip_list;
3975 struct ctdb_addr_info addr_info;
3976 unsigned int mask, i;
3977 int ret, retries = 0;
3979 if (argc != 2) {
3980 usage("addip");
3983 ret = ctdb_sock_addr_mask_from_string(argv[0], &addr, &mask);
3984 if (ret != 0) {
3985 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3986 return 1;
3989 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3990 ctdb->cmd_pnn, TIMEOUT(),
3991 false, &pubip_list);
3992 if (ret != 0) {
3993 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3994 ctdb->cmd_pnn);
3995 return 1;
3998 for (i=0; i<pubip_list->num; i++) {
3999 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
4000 fprintf(stderr, "Node already knows about IP %s\n",
4001 ctdb_sock_addr_to_string(mem_ctx,
4002 &addr, false));
4003 return 0;
4007 addr_info.addr = addr;
4008 addr_info.mask = mask;
4009 addr_info.iface = argv[1];
4011 while (retries < 5) {
4012 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4013 ctdb->cmd_pnn, TIMEOUT(),
4014 &addr_info);
4015 if (ret == 0) {
4016 break;
4019 sleep(3);
4020 retries++;
4023 if (ret != 0) {
4024 fprintf(stderr, "Failed to add public IP to node %u."
4025 " Giving up\n", ctdb->cmd_pnn);
4026 return ret;
4029 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
4030 if (ret != 0) {
4031 return ret;
4034 return 0;
4037 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4038 int argc, const char **argv)
4040 ctdb_sock_addr addr;
4041 struct ctdb_public_ip_list *pubip_list;
4042 struct ctdb_addr_info addr_info;
4043 unsigned int i;
4044 int ret;
4046 if (argc != 1) {
4047 usage("delip");
4050 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
4051 if (ret != 0) {
4052 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
4053 return 1;
4056 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
4057 ctdb->cmd_pnn, TIMEOUT(),
4058 false, &pubip_list);
4059 if (ret != 0) {
4060 fprintf(stderr, "Failed to get Public IPs from node %u\n",
4061 ctdb->cmd_pnn);
4062 return 1;
4065 for (i=0; i<pubip_list->num; i++) {
4066 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
4067 break;
4071 if (i == pubip_list->num) {
4072 fprintf(stderr, "Node does not know about IP address %s\n",
4073 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
4074 return 0;
4077 addr_info.addr = addr;
4078 addr_info.mask = 0;
4079 addr_info.iface = NULL;
4081 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4082 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
4083 if (ret != 0) {
4084 fprintf(stderr, "Failed to delete public IP from node %u\n",
4085 ctdb->cmd_pnn);
4086 return ret;
4089 return 0;
4092 #define DB_VERSION 3
4093 #define MAX_DB_NAME 64
4094 #define MAX_REC_BUFFER_SIZE (100*1000)
4096 struct db_header {
4097 unsigned long version;
4098 time_t timestamp;
4099 unsigned long flags;
4100 unsigned long nbuf;
4101 unsigned long nrec;
4102 char name[MAX_DB_NAME];
4105 struct backup_state {
4106 TALLOC_CTX *mem_ctx;
4107 struct ctdb_rec_buffer *recbuf;
4108 uint32_t db_id;
4109 int fd;
4110 unsigned int nbuf, nrec;
4113 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4114 TDB_DATA key, TDB_DATA data, void *private_data)
4116 struct backup_state *state = (struct backup_state *)private_data;
4117 size_t len;
4118 int ret;
4120 if (state->recbuf == NULL) {
4121 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4122 state->db_id);
4123 if (state->recbuf == NULL) {
4124 return ENOMEM;
4128 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4129 header, key, data);
4130 if (ret != 0) {
4131 return ret;
4134 len = ctdb_rec_buffer_len(state->recbuf);
4135 if (len < MAX_REC_BUFFER_SIZE) {
4136 return 0;
4139 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4140 if (ret != 0) {
4141 fprintf(stderr, "Failed to write records to backup file\n");
4142 return ret;
4145 state->nbuf += 1;
4146 state->nrec += state->recbuf->count;
4147 TALLOC_FREE(state->recbuf);
4149 return 0;
4152 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4153 int argc, const char **argv)
4155 const char *db_name;
4156 struct ctdb_db_context *db;
4157 uint32_t db_id;
4158 uint8_t db_flags;
4159 struct backup_state state;
4160 struct db_header db_hdr;
4161 int fd, ret;
4163 if (argc != 2) {
4164 usage("backupdb");
4167 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4168 return 1;
4171 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4172 db_flags, &db);
4173 if (ret != 0) {
4174 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4175 return ret;
4178 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4179 if (fd == -1) {
4180 ret = errno;
4181 fprintf(stderr, "Failed to open file %s for writing\n",
4182 argv[1]);
4183 return ret;
4186 /* Write empty header first */
4187 ZERO_STRUCT(db_hdr);
4188 ret = write(fd, &db_hdr, sizeof(struct db_header));
4189 if (ret == -1) {
4190 ret = errno;
4191 close(fd);
4192 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4193 return ret;
4196 state.mem_ctx = mem_ctx;
4197 state.recbuf = NULL;
4198 state.fd = fd;
4199 state.nbuf = 0;
4200 state.nrec = 0;
4202 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4203 if (ret != 0) {
4204 fprintf(stderr, "Failed to collect records from DB %s\n",
4205 db_name);
4206 close(fd);
4207 return ret;
4210 if (state.recbuf != NULL) {
4211 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4212 if (ret != 0) {
4213 fprintf(stderr,
4214 "Failed to write records to backup file\n");
4215 close(fd);
4216 return ret;
4219 state.nbuf += 1;
4220 state.nrec += state.recbuf->count;
4221 TALLOC_FREE(state.recbuf);
4224 db_hdr.version = DB_VERSION;
4225 db_hdr.timestamp = time(NULL);
4226 db_hdr.flags = db_flags;
4227 db_hdr.nbuf = state.nbuf;
4228 db_hdr.nrec = state.nrec;
4229 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4231 lseek(fd, 0, SEEK_SET);
4232 ret = write(fd, &db_hdr, sizeof(struct db_header));
4233 if (ret == -1) {
4234 ret = errno;
4235 close(fd);
4236 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4237 return ret;
4240 close(fd);
4241 printf("Database backed up to %s\n", argv[1]);
4242 return 0;
4245 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4246 int argc, const char **argv)
4248 const char *db_name = NULL;
4249 struct ctdb_db_context *db;
4250 struct db_header db_hdr;
4251 struct ctdb_node_map *nodemap;
4252 struct ctdb_req_control request;
4253 struct ctdb_reply_control **reply;
4254 struct ctdb_transdb wipedb;
4255 struct ctdb_pulldb_ext pulldb;
4256 struct ctdb_rec_buffer *recbuf;
4257 uint32_t generation;
4258 uint32_t *pnn_list;
4259 char timebuf[128];
4260 ssize_t n;
4261 int fd;
4262 unsigned long i, count;
4263 int ret;
4264 uint8_t db_flags;
4266 if (argc < 1 || argc > 2) {
4267 usage("restoredb");
4270 fd = open(argv[0], O_RDONLY, 0600);
4271 if (fd == -1) {
4272 ret = errno;
4273 fprintf(stderr, "Failed to open file %s for reading\n",
4274 argv[0]);
4275 return ret;
4278 if (argc == 2) {
4279 db_name = argv[1];
4282 n = read(fd, &db_hdr, sizeof(struct db_header));
4283 if (n == -1) {
4284 ret = errno;
4285 close(fd);
4286 fprintf(stderr, "Failed to read db header from file %s\n",
4287 argv[0]);
4288 return ret;
4290 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4292 if (db_hdr.version != DB_VERSION) {
4293 fprintf(stderr,
4294 "Wrong version of backup file, expected %u, got %lu\n",
4295 DB_VERSION, db_hdr.version);
4296 close(fd);
4297 return EINVAL;
4300 if (db_name == NULL) {
4301 db_name = db_hdr.name;
4304 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4305 localtime(&db_hdr.timestamp));
4306 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4308 db_flags = db_hdr.flags & 0xff;
4309 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4310 db_flags, &db);
4311 if (ret != 0) {
4312 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4313 close(fd);
4314 return ret;
4317 nodemap = get_nodemap(ctdb, false);
4318 if (nodemap == NULL) {
4319 fprintf(stderr, "Failed to get nodemap\n");
4320 close(fd);
4321 return ENOMEM;
4324 ret = get_generation(mem_ctx, ctdb, &generation);
4325 if (ret != 0) {
4326 fprintf(stderr, "Failed to get current generation\n");
4327 close(fd);
4328 return ret;
4331 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4332 &pnn_list);
4333 if (count <= 0) {
4334 close(fd);
4335 return ENOMEM;
4338 wipedb.db_id = ctdb_db_id(db);
4339 wipedb.tid = generation;
4341 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4342 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4343 ctdb->client, pnn_list, count,
4344 TIMEOUT(), &request, NULL, NULL);
4345 if (ret != 0) {
4346 goto failed;
4350 ctdb_req_control_db_transaction_start(&request, &wipedb);
4351 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4352 pnn_list, count, TIMEOUT(),
4353 &request, NULL, NULL);
4354 if (ret != 0) {
4355 goto failed;
4358 ctdb_req_control_wipe_database(&request, &wipedb);
4359 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4360 pnn_list, count, TIMEOUT(),
4361 &request, NULL, NULL);
4362 if (ret != 0) {
4363 goto failed;
4366 pulldb.db_id = ctdb_db_id(db);
4367 pulldb.lmaster = 0;
4368 pulldb.srvid = SRVID_CTDB_PUSHDB;
4370 ctdb_req_control_db_push_start(&request, &pulldb);
4371 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4372 pnn_list, count, TIMEOUT(),
4373 &request, NULL, NULL);
4374 if (ret != 0) {
4375 goto failed;
4378 for (i=0; i<db_hdr.nbuf; i++) {
4379 struct ctdb_req_message message;
4380 TDB_DATA data;
4381 size_t np;
4383 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4384 if (ret != 0) {
4385 goto failed;
4388 data.dsize = ctdb_rec_buffer_len(recbuf);
4389 data.dptr = talloc_size(mem_ctx, data.dsize);
4390 if (data.dptr == NULL) {
4391 goto failed;
4394 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4396 message.srvid = pulldb.srvid;
4397 message.data.data = data;
4399 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4400 ctdb->client,
4401 pnn_list, count,
4402 &message, NULL);
4403 if (ret != 0) {
4404 goto failed;
4407 talloc_free(recbuf);
4408 talloc_free(data.dptr);
4411 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4412 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4413 pnn_list, count, TIMEOUT(),
4414 &request, NULL, &reply);
4415 if (ret != 0) {
4416 goto failed;
4419 for (i=0; i<count; i++) {
4420 uint32_t num_records;
4422 ret = ctdb_reply_control_db_push_confirm(reply[i],
4423 &num_records);
4424 if (ret != 0) {
4425 fprintf(stderr, "Invalid response from node %u\n",
4426 pnn_list[i]);
4427 goto failed;
4430 if (num_records != db_hdr.nrec) {
4431 fprintf(stderr, "Node %u received %u of %lu records\n",
4432 pnn_list[i], num_records, db_hdr.nrec);
4433 goto failed;
4437 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4438 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4439 pnn_list, count, TIMEOUT(),
4440 &request, NULL, NULL);
4441 if (ret != 0) {
4442 goto failed;
4445 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4446 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4447 pnn_list, count, TIMEOUT(),
4448 &request, NULL, NULL);
4449 if (ret != 0) {
4450 goto failed;
4453 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4454 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4455 ctdb->client, pnn_list, count,
4456 TIMEOUT(), &request, NULL, NULL);
4457 if (ret != 0) {
4458 goto failed;
4461 printf("Database %s restored\n", db_name);
4462 close(fd);
4463 return 0;
4466 failed:
4467 close(fd);
4468 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4469 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4470 return ret;
4473 struct dumpdbbackup_state {
4474 ctdb_rec_parser_func_t parser;
4475 struct dump_record_state sub_state;
4478 static int dumpdbbackup_handler(uint32_t reqid,
4479 struct ctdb_ltdb_header *header,
4480 TDB_DATA key, TDB_DATA data,
4481 void *private_data)
4483 struct dumpdbbackup_state *state =
4484 (struct dumpdbbackup_state *)private_data;
4485 struct ctdb_ltdb_header hdr;
4486 int ret;
4488 ret = ctdb_ltdb_header_extract(&data, &hdr);
4489 if (ret != 0) {
4490 return ret;
4493 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4496 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4497 int argc, const char **argv)
4499 struct db_header db_hdr;
4500 char timebuf[128];
4501 struct dumpdbbackup_state state;
4502 ssize_t n;
4503 unsigned long i;
4504 int fd, ret;
4506 if (argc != 1) {
4507 usage("dumpbackup");
4510 fd = open(argv[0], O_RDONLY, 0600);
4511 if (fd == -1) {
4512 ret = errno;
4513 fprintf(stderr, "Failed to open file %s for reading\n",
4514 argv[0]);
4515 return ret;
4518 n = read(fd, &db_hdr, sizeof(struct db_header));
4519 if (n == -1) {
4520 ret = errno;
4521 close(fd);
4522 fprintf(stderr, "Failed to read db header from file %s\n",
4523 argv[0]);
4524 return ret;
4526 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4528 if (db_hdr.version != DB_VERSION) {
4529 fprintf(stderr,
4530 "Wrong version of backup file, expected %u, got %lu\n",
4531 DB_VERSION, db_hdr.version);
4532 close(fd);
4533 return EINVAL;
4536 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4537 localtime(&db_hdr.timestamp));
4538 printf("Dumping database %s from backup @ %s\n",
4539 db_hdr.name, timebuf);
4541 state.parser = dump_record;
4542 state.sub_state.count = 0;
4544 for (i=0; i<db_hdr.nbuf; i++) {
4545 struct ctdb_rec_buffer *recbuf;
4547 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4548 if (ret != 0) {
4549 fprintf(stderr, "Failed to read records\n");
4550 close(fd);
4551 return ret;
4554 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4555 &state);
4556 if (ret != 0) {
4557 fprintf(stderr, "Failed to dump records\n");
4558 close(fd);
4559 return ret;
4563 close(fd);
4564 printf("Dumped %u record(s)\n", state.sub_state.count);
4565 return 0;
4568 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4569 int argc, const char **argv)
4571 const char *db_name;
4572 struct ctdb_db_context *db;
4573 uint32_t db_id;
4574 uint8_t db_flags;
4575 struct ctdb_node_map *nodemap;
4576 struct ctdb_req_control request;
4577 struct ctdb_transdb wipedb;
4578 uint32_t generation;
4579 uint32_t *pnn_list;
4580 int count, ret;
4582 if (argc != 1) {
4583 usage("wipedb");
4586 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4587 return 1;
4590 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4591 db_flags, &db);
4592 if (ret != 0) {
4593 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4594 return ret;
4597 nodemap = get_nodemap(ctdb, false);
4598 if (nodemap == NULL) {
4599 fprintf(stderr, "Failed to get nodemap\n");
4600 return ENOMEM;
4603 ret = get_generation(mem_ctx, ctdb, &generation);
4604 if (ret != 0) {
4605 fprintf(stderr, "Failed to get current generation\n");
4606 return ret;
4609 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4610 &pnn_list);
4611 if (count <= 0) {
4612 return ENOMEM;
4615 ctdb_req_control_db_freeze(&request, db_id);
4616 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4617 ctdb->client, pnn_list, count,
4618 TIMEOUT(), &request, NULL, NULL);
4619 if (ret != 0) {
4620 goto failed;
4623 wipedb.db_id = db_id;
4624 wipedb.tid = generation;
4626 ctdb_req_control_db_transaction_start(&request, &wipedb);
4627 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4628 pnn_list, count, TIMEOUT(),
4629 &request, NULL, NULL);
4630 if (ret != 0) {
4631 goto failed;
4634 ctdb_req_control_wipe_database(&request, &wipedb);
4635 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4636 pnn_list, count, TIMEOUT(),
4637 &request, NULL, NULL);
4638 if (ret != 0) {
4639 goto failed;
4642 ctdb_req_control_db_set_healthy(&request, db_id);
4643 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4644 pnn_list, count, TIMEOUT(),
4645 &request, NULL, NULL);
4646 if (ret != 0) {
4647 goto failed;
4650 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4651 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4652 pnn_list, count, TIMEOUT(),
4653 &request, NULL, NULL);
4654 if (ret != 0) {
4655 goto failed;
4658 ctdb_req_control_db_thaw(&request, db_id);
4659 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4660 ctdb->client, pnn_list, count,
4661 TIMEOUT(), &request, NULL, NULL);
4662 if (ret != 0) {
4663 goto failed;
4666 printf("Database %s wiped\n", db_name);
4667 return 0;
4670 failed:
4671 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4672 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4673 return ret;
4676 static int control_leader(TALLOC_CTX *mem_ctx,
4677 struct ctdb_context *ctdb,
4678 int argc,
4679 const char **argv)
4681 uint32_t leader;
4682 int ret;
4684 ret = get_leader(mem_ctx, ctdb, &leader);
4685 if (ret != 0) {
4686 return ret;
4689 print_pnn(leader);
4691 return 0;
4694 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4695 int argc, const char **argv)
4697 char *t, *event_helper = NULL;
4699 t = getenv("CTDB_EVENT_HELPER");
4700 if (t != NULL) {
4701 event_helper = talloc_strdup(mem_ctx, t);
4702 } else {
4703 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb-event",
4704 CTDB_HELPER_BINDIR);
4707 if (event_helper == NULL) {
4708 fprintf(stderr, "Unable to set event daemon helper\n");
4709 return 1;
4712 return run_helper(mem_ctx, "event daemon helper", event_helper,
4713 argc, argv);
4716 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4717 int argc, const char **argv)
4719 const char *new_argv[4];
4721 if (argc > 1) {
4722 usage("scriptstatus");
4725 new_argv[0] = "status";
4726 new_argv[1] = "legacy";
4727 new_argv[2] = (argc == 0) ? "monitor" : argv[0];
4728 new_argv[3] = NULL;
4730 (void) control_event(mem_ctx, ctdb, 3, new_argv);
4731 return 0;
4734 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4735 int argc, const char **argv)
4737 char *t, *natgw_helper = NULL;
4739 if (argc != 1) {
4740 usage("natgw");
4743 t = getenv("CTDB_NATGW_HELPER");
4744 if (t != NULL) {
4745 natgw_helper = talloc_strdup(mem_ctx, t);
4746 } else {
4747 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4748 CTDB_HELPER_BINDIR);
4751 if (natgw_helper == NULL) {
4752 fprintf(stderr, "Unable to set NAT gateway helper\n");
4753 return 1;
4756 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4757 argc, argv);
4761 * Find the PNN of the current node
4762 * discover the pnn by loading the nodes file and try to bind
4763 * to all addresses one at a time until the ip address is found.
4765 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4767 struct ctdb_node_map *nodemap;
4768 unsigned int i;
4770 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4771 if (nodemap == NULL) {
4772 return false;
4775 for (i=0; i<nodemap->num; i++) {
4776 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4777 continue;
4779 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4780 if (pnn != NULL) {
4781 *pnn = nodemap->node[i].pnn;
4783 talloc_free(nodemap);
4784 return true;
4788 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4789 talloc_free(nodemap);
4790 return false;
4793 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4794 int argc, const char **argv)
4796 const char *reclock;
4797 int ret;
4799 if (argc != 0) {
4800 usage("getreclock");
4803 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4804 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4805 if (ret != 0) {
4806 return ret;
4809 if (reclock != NULL) {
4810 printf("%s\n", reclock);
4813 return 0;
4816 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4817 struct ctdb_context *ctdb,
4818 int argc, const char **argv)
4820 uint32_t lmasterrole = 0;
4821 int ret;
4823 if (argc != 1) {
4824 usage("setlmasterrole");
4827 if (strcmp(argv[0], "on") == 0) {
4828 lmasterrole = 1;
4829 } else if (strcmp(argv[0], "off") == 0) {
4830 lmasterrole = 0;
4831 } else {
4832 usage("setlmasterrole");
4835 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4836 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4837 if (ret != 0) {
4838 return ret;
4841 return 0;
4844 static int control_setleaderrole(TALLOC_CTX *mem_ctx,
4845 struct ctdb_context *ctdb,
4846 int argc,
4847 const char **argv)
4849 uint32_t leaderrole = 0;
4850 int ret;
4852 if (argc != 1) {
4853 usage("setleaderrole");
4856 if (strcmp(argv[0], "on") == 0) {
4857 leaderrole = 1;
4858 } else if (strcmp(argv[0], "off") == 0) {
4859 leaderrole = 0;
4860 } else {
4861 usage("setleaderrole");
4864 ret = ctdb_ctrl_set_recmasterrole(mem_ctx,
4865 ctdb->ev,
4866 ctdb->client,
4867 ctdb->cmd_pnn,
4868 TIMEOUT(),
4869 leaderrole);
4870 if (ret != 0) {
4871 return ret;
4874 return 0;
4877 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4878 struct ctdb_context *ctdb,
4879 int argc, const char **argv)
4881 uint32_t db_id;
4882 uint8_t db_flags;
4883 int ret;
4885 if (argc != 1) {
4886 usage("setdbreadonly");
4889 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4890 return 1;
4893 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4894 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4895 return 1;
4898 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4899 ctdb->cmd_pnn, TIMEOUT(), db_id);
4900 if (ret != 0) {
4901 return ret;
4904 return 0;
4907 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4908 int argc, const char **argv)
4910 uint32_t db_id;
4911 uint8_t db_flags;
4912 int ret;
4914 if (argc != 1) {
4915 usage("setdbsticky");
4918 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4919 return 1;
4922 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4923 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4924 return 1;
4927 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4928 ctdb->cmd_pnn, TIMEOUT(), db_id);
4929 if (ret != 0) {
4930 return ret;
4933 return 0;
4936 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4937 int argc, const char **argv)
4939 const char *db_name;
4940 struct ctdb_db_context *db;
4941 struct ctdb_transaction_handle *h;
4942 uint8_t db_flags;
4943 TDB_DATA key, data;
4944 int ret;
4946 if (argc != 2) {
4947 usage("pfetch");
4950 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4951 return 1;
4954 if (! (db_flags &
4955 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4956 fprintf(stderr, "Transactions not supported on DB %s\n",
4957 db_name);
4958 return 1;
4961 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4962 db_flags, &db);
4963 if (ret != 0) {
4964 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4965 return ret;
4968 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4969 if (ret != 0) {
4970 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4971 return ret;
4974 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4975 TIMEOUT(), db, true, &h);
4976 if (ret != 0) {
4977 fprintf(stderr, "Failed to start transaction on db %s\n",
4978 db_name);
4979 return ret;
4982 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4983 if (ret != 0) {
4984 fprintf(stderr, "Failed to read record for key %s\n",
4985 argv[1]);
4986 ctdb_transaction_cancel(h);
4987 return ret;
4990 printf("%.*s\n", (int)data.dsize, data.dptr);
4992 ctdb_transaction_cancel(h);
4993 return 0;
4996 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4997 int argc, const char **argv)
4999 const char *db_name;
5000 struct ctdb_db_context *db;
5001 struct ctdb_transaction_handle *h;
5002 uint8_t db_flags;
5003 TDB_DATA key, data;
5004 int ret;
5006 if (argc != 3) {
5007 usage("pstore");
5010 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5011 return 1;
5014 if (! (db_flags &
5015 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5016 fprintf(stderr, "Transactions not supported on DB %s\n",
5017 db_name);
5018 return 1;
5021 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5022 db_flags, &db);
5023 if (ret != 0) {
5024 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5025 return ret;
5028 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5029 if (ret != 0) {
5030 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5031 return ret;
5034 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5035 if (ret != 0) {
5036 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5037 return ret;
5040 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5041 TIMEOUT(), db, false, &h);
5042 if (ret != 0) {
5043 fprintf(stderr, "Failed to start transaction on db %s\n",
5044 db_name);
5045 return ret;
5048 ret = ctdb_transaction_store_record(h, key, data);
5049 if (ret != 0) {
5050 fprintf(stderr, "Failed to store record for key %s\n",
5051 argv[1]);
5052 ctdb_transaction_cancel(h);
5053 return ret;
5056 ret = ctdb_transaction_commit(h);
5057 if (ret != 0) {
5058 fprintf(stderr, "Failed to commit transaction on db %s\n",
5059 db_name);
5060 ctdb_transaction_cancel(h);
5061 return ret;
5064 return 0;
5067 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5068 int argc, const char **argv)
5070 const char *db_name;
5071 struct ctdb_db_context *db;
5072 struct ctdb_transaction_handle *h;
5073 uint8_t db_flags;
5074 TDB_DATA key;
5075 int ret;
5077 if (argc != 2) {
5078 usage("pdelete");
5081 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5082 return 1;
5085 if (! (db_flags &
5086 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5087 fprintf(stderr, "Transactions not supported on DB %s\n",
5088 db_name);
5089 return 1;
5092 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5093 db_flags, &db);
5094 if (ret != 0) {
5095 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5096 return ret;
5099 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5100 if (ret != 0) {
5101 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5102 return ret;
5105 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5106 TIMEOUT(), db, false, &h);
5107 if (ret != 0) {
5108 fprintf(stderr, "Failed to start transaction on db %s\n",
5109 db_name);
5110 return ret;
5113 ret = ctdb_transaction_delete_record(h, key);
5114 if (ret != 0) {
5115 fprintf(stderr, "Failed to delete record for key %s\n",
5116 argv[1]);
5117 ctdb_transaction_cancel(h);
5118 return ret;
5121 ret = ctdb_transaction_commit(h);
5122 if (ret != 0) {
5123 fprintf(stderr, "Failed to commit transaction on db %s\n",
5124 db_name);
5125 ctdb_transaction_cancel(h);
5126 return ret;
5129 return 0;
5132 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5134 const char *t;
5135 size_t n;
5136 int ret;
5138 *data = tdb_null;
5140 /* Skip whitespace */
5141 n = strspn(*ptr, " \t");
5142 t = *ptr + n;
5144 if (t[0] == '"') {
5145 /* Quoted ASCII string - no wide characters! */
5146 t++;
5147 n = strcspn(t, "\"");
5148 if (t[n] == '"') {
5149 if (n > 0) {
5150 ret = str_to_data(t, n, mem_ctx, data);
5151 if (ret != 0) {
5152 return ret;
5155 *ptr = t + n + 1;
5156 } else {
5157 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5158 return 1;
5160 } else {
5161 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5162 return 1;
5165 return 0;
5168 #define MAX_LINE_SIZE 1024
5170 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5171 TDB_DATA *key, TDB_DATA *value)
5173 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5174 const char *ptr;
5175 int ret;
5177 ptr = fgets(line, MAX_LINE_SIZE, file);
5178 if (ptr == NULL) {
5179 return false;
5182 /* Get key */
5183 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5184 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5185 /* Line Ignored but not EOF */
5186 *key = tdb_null;
5187 return true;
5190 /* Get value */
5191 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5192 if (ret != 0) {
5193 /* Line Ignored but not EOF */
5194 talloc_free(key->dptr);
5195 *key = tdb_null;
5196 return true;
5199 return true;
5202 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5203 int argc, const char **argv)
5205 const char *db_name;
5206 struct ctdb_db_context *db;
5207 struct ctdb_transaction_handle *h;
5208 uint8_t db_flags;
5209 FILE *file;
5210 TDB_DATA key = tdb_null, value = tdb_null;
5211 int ret;
5213 if (argc < 1 || argc > 2) {
5214 usage("ptrans");
5217 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5218 return 1;
5221 if (! (db_flags &
5222 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5223 fprintf(stderr, "Transactions not supported on DB %s\n",
5224 db_name);
5225 return 1;
5228 if (argc == 2) {
5229 file = fopen(argv[1], "r");
5230 if (file == NULL) {
5231 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5232 return 1;
5234 } else {
5235 file = stdin;
5238 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5239 db_flags, &db);
5240 if (ret != 0) {
5241 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5242 goto done;
5245 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5246 TIMEOUT(), db, false, &h);
5247 if (ret != 0) {
5248 fprintf(stderr, "Failed to start transaction on db %s\n",
5249 db_name);
5250 goto done;
5253 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5254 if (key.dsize != 0) {
5255 ret = ctdb_transaction_store_record(h, key, value);
5256 if (ret != 0) {
5257 fprintf(stderr, "Failed to store record\n");
5258 ctdb_transaction_cancel(h);
5259 goto done;
5261 talloc_free(key.dptr);
5262 talloc_free(value.dptr);
5266 ret = ctdb_transaction_commit(h);
5267 if (ret != 0) {
5268 fprintf(stderr, "Failed to commit transaction on db %s\n",
5269 db_name);
5270 ctdb_transaction_cancel(h);
5273 done:
5274 if (file != stdin) {
5275 fclose(file);
5277 return ret;
5280 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5281 int argc, const char **argv)
5283 struct tdb_context *tdb;
5284 TDB_DATA key, data;
5285 struct ctdb_ltdb_header header;
5286 int ret;
5288 if (argc < 2 || argc > 3) {
5289 usage("tfetch");
5292 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5293 if (tdb == NULL) {
5294 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5295 return 1;
5298 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5299 if (ret != 0) {
5300 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5301 tdb_close(tdb);
5302 return ret;
5305 data = tdb_fetch(tdb, key);
5306 if (data.dptr == NULL) {
5307 fprintf(stderr, "No record for key %s\n", argv[1]);
5308 tdb_close(tdb);
5309 return 1;
5312 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5313 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5314 tdb_close(tdb);
5315 return 1;
5318 tdb_close(tdb);
5320 if (argc == 3) {
5321 int fd;
5322 ssize_t nwritten;
5324 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5325 if (fd == -1) {
5326 fprintf(stderr, "Failed to open output file %s\n",
5327 argv[2]);
5328 goto fail;
5331 nwritten = sys_write(fd, data.dptr, data.dsize);
5332 if (nwritten == -1 ||
5333 (size_t)nwritten != data.dsize) {
5334 fprintf(stderr, "Failed to write record to file\n");
5335 close(fd);
5336 goto fail;
5339 close(fd);
5342 fail:
5343 ret = ctdb_ltdb_header_extract(&data, &header);
5344 if (ret != 0) {
5345 fprintf(stderr, "Failed to parse header from data\n");
5346 return 1;
5349 dump_ltdb_header(&header);
5350 dump_tdb_data("data", data);
5352 return 0;
5355 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5356 int argc, const char **argv)
5358 struct tdb_context *tdb;
5359 TDB_DATA key, data[2], value;
5360 struct ctdb_ltdb_header header;
5361 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5362 size_t np;
5363 int ret = 0;
5365 if (argc < 3 || argc > 5) {
5366 usage("tstore");
5369 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5370 if (tdb == NULL) {
5371 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5372 return 1;
5375 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5376 if (ret != 0) {
5377 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5378 tdb_close(tdb);
5379 return ret;
5382 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5383 if (ret != 0) {
5384 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5385 tdb_close(tdb);
5386 return ret;
5389 ZERO_STRUCT(header);
5391 if (argc > 3) {
5392 header.rsn = (uint64_t)smb_strtoull(argv[3],
5393 NULL,
5395 &ret,
5396 SMB_STR_STANDARD);
5397 if (ret != 0) {
5398 return ret;
5401 if (argc > 4) {
5402 header.dmaster = (uint32_t)atol(argv[4]);
5404 if (argc > 5) {
5405 header.flags = (uint32_t)atol(argv[5]);
5408 ctdb_ltdb_header_push(&header, header_buf, &np);
5410 data[0].dsize = np;
5411 data[0].dptr = header_buf;
5413 data[1].dsize = value.dsize;
5414 data[1].dptr = value.dptr;
5416 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5417 if (ret != 0) {
5418 fprintf(stderr, "Failed to write record %s to file %s\n",
5419 argv[1], argv[0]);
5422 tdb_close(tdb);
5424 return ret;
5427 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5428 int argc, const char **argv)
5430 const char *db_name;
5431 struct ctdb_db_context *db;
5432 struct ctdb_record_handle *h;
5433 uint8_t db_flags;
5434 TDB_DATA key, data;
5435 bool readonly = false;
5436 int ret;
5438 if (argc < 2 || argc > 3) {
5439 usage("readkey");
5442 if (argc == 3) {
5443 if (strcmp(argv[2], "readonly") == 0) {
5444 readonly = true;
5445 } else {
5446 usage("readkey");
5450 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5451 return 1;
5454 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5455 fprintf(stderr, "DB %s is not a volatile database\n",
5456 db_name);
5457 return 1;
5460 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5461 db_flags, &db);
5462 if (ret != 0) {
5463 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5464 return ret;
5467 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5468 if (ret != 0) {
5469 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5470 return ret;
5473 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5474 db, key, readonly, &h, NULL, &data);
5475 if (ret != 0) {
5476 fprintf(stderr, "Failed to read record for key %s\n",
5477 argv[1]);
5478 } else {
5479 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5480 (int)data.dsize, data.dptr);
5483 talloc_free(h);
5484 return ret;
5487 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5488 int argc, const char **argv)
5490 const char *db_name;
5491 struct ctdb_db_context *db;
5492 struct ctdb_record_handle *h;
5493 uint8_t db_flags;
5494 TDB_DATA key, data;
5495 int ret;
5497 if (argc != 3) {
5498 usage("writekey");
5501 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5502 return 1;
5505 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5506 fprintf(stderr, "DB %s is not a volatile database\n",
5507 db_name);
5508 return 1;
5511 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5512 db_flags, &db);
5513 if (ret != 0) {
5514 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5515 return ret;
5518 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5519 if (ret != 0) {
5520 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5521 return ret;
5524 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5525 if (ret != 0) {
5526 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5527 return ret;
5530 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5531 db, key, false, &h, NULL, NULL);
5532 if (ret != 0) {
5533 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5534 return ret;
5537 ret = ctdb_store_record(h, data);
5538 if (ret != 0) {
5539 fprintf(stderr, "Failed to store record for key %s\n",
5540 argv[1]);
5543 talloc_free(h);
5544 return ret;
5547 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5548 int argc, const char **argv)
5550 const char *db_name;
5551 struct ctdb_db_context *db;
5552 struct ctdb_record_handle *h;
5553 uint8_t db_flags;
5554 TDB_DATA key, data;
5555 int ret;
5557 if (argc != 2) {
5558 usage("deletekey");
5561 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5562 return 1;
5565 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5566 fprintf(stderr, "DB %s is not a volatile database\n",
5567 db_name);
5568 return 1;
5571 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5572 db_flags, &db);
5573 if (ret != 0) {
5574 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5575 return ret;
5578 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5579 if (ret != 0) {
5580 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5581 return ret;
5584 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5585 db, key, false, &h, NULL, &data);
5586 if (ret != 0) {
5587 fprintf(stderr, "Failed to fetch record for key %s\n",
5588 argv[1]);
5589 return ret;
5592 ret = ctdb_delete_record(h);
5593 if (ret != 0) {
5594 fprintf(stderr, "Failed to delete record for key %s\n",
5595 argv[1]);
5598 talloc_free(h);
5599 return ret;
5602 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5603 int argc, const char **argv)
5605 struct sockaddr_in sin;
5606 unsigned int port;
5607 int s, v;
5608 int ret;
5610 if (argc != 1) {
5611 usage("chktcpport");
5614 port = atoi(argv[0]);
5616 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5617 if (s == -1) {
5618 fprintf(stderr, "Failed to open local socket\n");
5619 return errno;
5622 v = fcntl(s, F_GETFL, 0);
5623 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5624 fprintf(stderr, "Unable to set socket non-blocking\n");
5625 close(s);
5626 return errno;
5629 bzero(&sin, sizeof(sin));
5630 sin.sin_family = AF_INET;
5631 sin.sin_port = htons(port);
5632 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5633 close(s);
5634 if (ret == -1) {
5635 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5636 return errno;
5639 return 0;
5642 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5643 int argc, const char **argv)
5645 uint32_t db_id;
5646 const char *db_name;
5647 uint64_t seqnum;
5648 int ret;
5650 if (argc != 1) {
5651 usage("getdbseqnum");
5654 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5655 return 1;
5658 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5659 ctdb->cmd_pnn, TIMEOUT(), db_id,
5660 &seqnum);
5661 if (ret != 0) {
5662 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5663 db_name);
5664 return ret;
5667 printf("0x%"PRIx64"\n", seqnum);
5668 return 0;
5671 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5672 int argc, const char **argv)
5674 const char *nodestring = NULL;
5675 struct ctdb_node_map *nodemap_in;
5676 struct ctdb_node_map *nodemap;
5677 unsigned int i;
5678 int ret;
5679 bool print_hdr = false;
5681 if (argc > 1) {
5682 usage("nodestatus");
5685 if (argc == 1) {
5686 nodestring = argv[0];
5687 if (strcmp(nodestring, "all") == 0) {
5688 print_hdr = true;
5692 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap_in)) {
5693 return 1;
5696 nodemap = get_nodemap_unknown(mem_ctx, ctdb, nodemap_in);
5697 if (nodemap == NULL) {
5698 return 1;
5701 if (options.machinereadable) {
5702 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5703 } else {
5704 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5707 ret = 0;
5708 for (i=0; i<nodemap->num; i++) {
5709 uint32_t flags = nodemap->node[i].flags;
5711 if ((flags & NODE_FLAGS_DELETED) != 0) {
5712 continue;
5715 ret |= flags;
5718 return ret;
5721 const struct {
5722 const char *name;
5723 uint32_t offset;
5724 } db_stats_fields[] = {
5725 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5726 DBSTATISTICS_FIELD(db_ro_delegations),
5727 DBSTATISTICS_FIELD(db_ro_revokes),
5728 DBSTATISTICS_FIELD(locks.num_calls),
5729 DBSTATISTICS_FIELD(locks.num_current),
5730 DBSTATISTICS_FIELD(locks.num_pending),
5731 DBSTATISTICS_FIELD(locks.num_failed),
5734 static void print_dbstatistics(const char *db_name,
5735 struct ctdb_db_statistics *s)
5737 size_t i;
5738 const char *prefix = NULL;
5739 int preflen = 0;
5741 printf("DB Statistics %s\n", db_name);
5743 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5744 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5745 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5746 if (! prefix ||
5747 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5748 prefix = db_stats_fields[i].name;
5749 printf(" %*.*s\n", preflen-1, preflen-1,
5750 db_stats_fields[i].name);
5752 } else {
5753 preflen = 0;
5755 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5756 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5757 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5760 printf(" hop_count_buckets:");
5761 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5762 printf(" %d", s->hop_count_bucket[i]);
5764 printf("\n");
5766 printf(" lock_buckets:");
5767 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5768 printf(" %d", s->locks.buckets[i]);
5770 printf("\n");
5772 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5773 "locks_latency MIN/AVG/MAX",
5774 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5775 s->locks.latency.max, s->locks.latency.num);
5777 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5778 "vacuum_latency MIN/AVG/MAX",
5779 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5780 s->vacuum.latency.max, s->vacuum.latency.num);
5782 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5783 for (i=0; i<s->num_hot_keys; i++) {
5784 size_t j;
5785 printf(" Count:%d Key:", s->hot_keys[i].count);
5786 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5787 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5789 printf("\n");
5793 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5794 int argc, const char **argv)
5796 uint32_t db_id;
5797 const char *db_name;
5798 struct ctdb_db_statistics *dbstats;
5799 int ret;
5801 if (argc != 1) {
5802 usage("dbstatistics");
5805 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5806 return 1;
5809 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5810 ctdb->cmd_pnn, TIMEOUT(), db_id,
5811 &dbstats);
5812 if (ret != 0) {
5813 fprintf(stderr, "Failed to get statistics for DB %s\n",
5814 db_name);
5815 return ret;
5818 print_dbstatistics(db_name, dbstats);
5819 return 0;
5822 struct disable_takeover_runs_state {
5823 uint32_t *pnn_list;
5824 unsigned int node_count;
5825 bool *reply;
5826 int status;
5827 bool done;
5830 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5831 void *private_data)
5833 struct disable_takeover_runs_state *state =
5834 (struct disable_takeover_runs_state *)private_data;
5835 unsigned int i;
5836 int ret;
5838 if (data.dsize != sizeof(int)) {
5839 /* Ignore packet */
5840 return;
5843 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5844 ret = *(int *)data.dptr;
5845 if (ret < 0) {
5846 state->status = ret;
5847 state->done = true;
5848 return;
5850 for (i=0; i<state->node_count; i++) {
5851 if (state->pnn_list[i] == (uint32_t)ret) {
5852 state->reply[i] = true;
5853 break;
5857 state->done = true;
5858 for (i=0; i<state->node_count; i++) {
5859 if (! state->reply[i]) {
5860 state->done = false;
5861 break;
5866 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5867 struct ctdb_context *ctdb, uint32_t timeout,
5868 uint32_t *pnn_list, int count)
5870 struct ctdb_disable_message disable = { 0 };
5871 struct disable_takeover_runs_state state;
5872 int ret, i;
5874 disable.pnn = ctdb->pnn;
5875 disable.srvid = next_srvid(ctdb);
5876 disable.timeout = timeout;
5878 state.pnn_list = pnn_list;
5879 state.node_count = count;
5880 state.done = false;
5881 state.status = 0;
5882 state.reply = talloc_zero_array(mem_ctx, bool, count);
5883 if (state.reply == NULL) {
5884 return ENOMEM;
5887 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5888 disable.srvid,
5889 disable_takeover_run_handler,
5890 &state);
5891 if (ret != 0) {
5892 return ret;
5895 for (i=0; i<count; i++) {
5896 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5897 ctdb->client,
5898 pnn_list[i],
5899 &disable);
5900 if (ret != 0) {
5901 goto fail;
5905 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5906 if (ret == ETIME) {
5907 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5908 } else {
5909 ret = (state.status >= 0 ? 0 : 1);
5912 fail:
5913 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5914 disable.srvid, &state);
5915 return ret;
5918 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5919 int argc, const char **argv)
5921 const char *nodestring = NULL;
5922 struct ctdb_node_map *nodemap, *nodemap2;
5923 struct ctdb_req_control request;
5924 uint32_t *pnn_list, *pnn_list2;
5925 int ret, count, count2;
5927 if (argc > 1) {
5928 usage("reloadips");
5931 if (argc == 1) {
5932 nodestring = argv[0];
5935 nodemap = get_nodemap(ctdb, false);
5936 if (nodemap == NULL) {
5937 return 1;
5940 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5941 return 1;
5944 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5945 mem_ctx, &pnn_list);
5946 if (count <= 0) {
5947 fprintf(stderr, "Memory allocation error\n");
5948 return 1;
5951 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5952 mem_ctx, &pnn_list2);
5953 if (count2 <= 0) {
5954 fprintf(stderr, "Memory allocation error\n");
5955 return 1;
5958 /* Disable takeover runs on all connected nodes. A reply
5959 * indicating success is needed from each node so all nodes
5960 * will need to be active.
5962 * A check could be added to not allow reloading of IPs when
5963 * there are disconnected nodes. However, this should
5964 * probably be left up to the administrator.
5966 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5967 pnn_list, count);
5968 if (ret != 0) {
5969 fprintf(stderr, "Failed to disable takeover runs\n");
5970 return ret;
5973 /* Now tell all the desired nodes to reload their public IPs.
5974 * Keep trying this until it succeeds. This assumes all
5975 * failures are transient, which might not be true...
5977 ctdb_req_control_reload_public_ips(&request);
5978 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5979 pnn_list2, count2, TIMEOUT(),
5980 &request, NULL, NULL);
5981 if (ret != 0) {
5982 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5985 /* It isn't strictly necessary to wait until takeover runs are
5986 * re-enabled but doing so can't hurt.
5988 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5989 if (ret != 0) {
5990 fprintf(stderr, "Failed to enable takeover runs\n");
5991 return ret;
5994 return ipreallocate(mem_ctx, ctdb);
5998 static const struct ctdb_cmd {
5999 const char *name;
6000 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
6001 bool without_daemon; /* can be run without daemon running ? */
6002 bool remote; /* can be run on remote nodes */
6003 const char *msg;
6004 const char *args;
6005 } ctdb_commands[] = {
6006 { "version", control_version, true, false,
6007 "show version of ctdb", NULL },
6008 { "status", control_status, false, true,
6009 "show node status", NULL },
6010 { "uptime", control_uptime, false, true,
6011 "show node uptime", NULL },
6012 { "ping", control_ping, false, true,
6013 "ping a node", NULL },
6014 { "runstate", control_runstate, false, true,
6015 "get/check runstate of a node",
6016 "[setup|first_recovery|startup|running]" },
6017 { "getvar", control_getvar, false, true,
6018 "get a tunable variable", "<name>" },
6019 { "setvar", control_setvar, false, true,
6020 "set a tunable variable", "<name> <value>" },
6021 { "listvars", control_listvars, false, true,
6022 "list tunable variables", NULL },
6023 { "statistics", control_statistics, false, true,
6024 "show ctdb statistics", NULL },
6025 { "statisticsreset", control_statistics_reset, false, true,
6026 "reset ctdb statistics", NULL },
6027 { "stats", control_stats, false, true,
6028 "show rolling statistics", "[count]" },
6029 { "ip", control_ip, false, true,
6030 "show public ips", "[all]" },
6031 { "ipinfo", control_ipinfo, false, true,
6032 "show public ip details", "<ip>" },
6033 { "ifaces", control_ifaces, false, true,
6034 "show interfaces", NULL },
6035 { "setifacelink", control_setifacelink, false, true,
6036 "set interface link status", "<iface> up|down" },
6037 { "process-exists", control_process_exists, false, true,
6038 "check if a process exists on a node", "<pid> [<srvid>]" },
6039 { "getdbmap", control_getdbmap, false, true,
6040 "show attached databases", NULL },
6041 { "getdbstatus", control_getdbstatus, false, true,
6042 "show database status", "<dbname|dbid>" },
6043 { "catdb", control_catdb, false, false,
6044 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6045 { "cattdb", control_cattdb, false, false,
6046 "dump local ctdb database", "<dbname|dbid>" },
6047 { "getcapabilities", control_getcapabilities, false, true,
6048 "show node capabilities", NULL },
6049 { "pnn", control_pnn, false, false,
6050 "show the pnn of the current node", NULL },
6051 { "lvs", control_lvs, false, false,
6052 "show lvs configuration", "leader|list|status" },
6053 { "setdebug", control_setdebug, false, true,
6054 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6055 { "getdebug", control_getdebug, false, true,
6056 "get debug level", NULL },
6057 { "attach", control_attach, false, false,
6058 "attach a database", "<dbname> [persistent|replicated]" },
6059 { "detach", control_detach, false, false,
6060 "detach database(s)", "<dbname|dbid> ..." },
6061 { "dumpmemory", control_dumpmemory, false, true,
6062 "dump ctdbd memory map", NULL },
6063 { "rddumpmemory", control_rddumpmemory, false, true,
6064 "dump recoverd memory map", NULL },
6065 { "getpid", control_getpid, false, true,
6066 "get ctdbd process ID", NULL },
6067 { "disable", control_disable, false, true,
6068 "disable a node", NULL },
6069 { "enable", control_enable, false, true,
6070 "enable a node", NULL },
6071 { "stop", control_stop, false, true,
6072 "stop a node", NULL },
6073 { "continue", control_continue, false, true,
6074 "continue a stopped node", NULL },
6075 { "ban", control_ban, false, true,
6076 "ban a node", "<bantime>"},
6077 { "unban", control_unban, false, true,
6078 "unban a node", NULL },
6079 { "shutdown", control_shutdown, false, true,
6080 "shutdown ctdb daemon", NULL },
6081 { "recover", control_recover, false, true,
6082 "force recovery", NULL },
6083 { "sync", control_ipreallocate, false, true,
6084 "run ip reallocation (deprecated)", NULL },
6085 { "ipreallocate", control_ipreallocate, false, true,
6086 "run ip reallocation", NULL },
6087 { "gratarp", control_gratarp, false, true,
6088 "send a gratuitous arp", "<ip> <interface>" },
6089 { "tickle", control_tickle, true, false,
6090 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6091 { "gettickles", control_gettickles, false, true,
6092 "get the list of tickles", "<ip> [<port>]" },
6093 { "addtickle", control_addtickle, false, true,
6094 "add a tickle", "<ip>:<port> <ip>:<port>" },
6095 { "deltickle", control_deltickle, false, true,
6096 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6097 { "listnodes", control_listnodes, true, true,
6098 "list nodes in the cluster", NULL },
6099 { "reloadnodes", control_reloadnodes, false, false,
6100 "reload the nodes file all nodes", NULL },
6101 { "moveip", control_moveip, false, false,
6102 "move an ip address to another node", "<ip> <node>" },
6103 { "addip", control_addip, false, true,
6104 "add an ip address to a node", "<ip/mask> <iface>" },
6105 { "delip", control_delip, false, true,
6106 "delete an ip address from a node", "<ip>" },
6107 { "backupdb", control_backupdb, false, false,
6108 "backup a database into a file", "<dbname|dbid> <file>" },
6109 { "restoredb", control_restoredb, false, false,
6110 "restore a database from a file", "<file> [dbname]" },
6111 { "dumpdbbackup", control_dumpdbbackup, true, false,
6112 "dump database from a backup file", "<file>" },
6113 { "wipedb", control_wipedb, false, false,
6114 "wipe the contents of a database.", "<dbname|dbid>"},
6115 { "leader", control_leader, false, true,
6116 "show the pnn of the leader", NULL },
6117 { "event", control_event, true, false,
6118 "event and event script commands", NULL },
6119 { "scriptstatus", control_scriptstatus, true, false,
6120 "show event script status",
6121 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6122 { "natgw", control_natgw, false, false,
6123 "show natgw configuration", "leader|list|status" },
6124 { "getreclock", control_getreclock, false, true,
6125 "get recovery lock file", NULL },
6126 { "setlmasterrole", control_setlmasterrole, false, true,
6127 "set LMASTER role", "on|off" },
6128 { "setleaderrole", control_setleaderrole, false, true,
6129 "set LEADER role", "on|off"},
6130 { "setdbreadonly", control_setdbreadonly, false, true,
6131 "enable readonly records", "<dbname|dbid>" },
6132 { "setdbsticky", control_setdbsticky, false, true,
6133 "enable sticky records", "<dbname|dbid>"},
6134 { "pfetch", control_pfetch, false, false,
6135 "fetch record from persistent database", "<dbname|dbid> <key>" },
6136 { "pstore", control_pstore, false, false,
6137 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6138 { "pdelete", control_pdelete, false, false,
6139 "delete record from persistent database", "<dbname|dbid> <key>" },
6140 { "ptrans", control_ptrans, false, false,
6141 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6142 { "tfetch", control_tfetch, false, true,
6143 "fetch a record", "<tdb-file> <key> [<file>]" },
6144 { "tstore", control_tstore, false, true,
6145 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6146 { "readkey", control_readkey, false, false,
6147 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6148 { "writekey", control_writekey, false, false,
6149 "write value for a database key", "<dbname|dbid> <key> <value>" },
6150 { "deletekey", control_deletekey, false, false,
6151 "delete a database key", "<dbname|dbid> <key>" },
6152 { "checktcpport", control_checktcpport, true, false,
6153 "check if a service is bound to a specific tcp port or not", "<port>" },
6154 { "getdbseqnum", control_getdbseqnum, false, false,
6155 "get database sequence number", "<dbname|dbid>" },
6156 { "nodestatus", control_nodestatus, false, true,
6157 "show and return node status", "[all|<pnn-list>]" },
6158 { "dbstatistics", control_dbstatistics, false, true,
6159 "show database statistics", "<dbname|dbid>" },
6160 { "reloadips", control_reloadips, false, false,
6161 "reload the public addresses file", "[all|<pnn-list>]" },
6164 static const struct ctdb_cmd *match_command(const char *command)
6166 const struct ctdb_cmd *cmd;
6167 size_t i;
6169 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6170 cmd = &ctdb_commands[i];
6171 if (strcmp(command, cmd->name) == 0) {
6172 return cmd;
6176 return NULL;
6181 * Show usage message
6183 static void usage_full(void)
6185 size_t i;
6187 poptPrintHelp(pc, stdout, 0);
6188 printf("\nCommands:\n");
6189 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6190 printf(" %-15s %-27s %s\n",
6191 ctdb_commands[i].name,
6192 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6193 ctdb_commands[i].msg);
6197 static void usage(const char *command)
6199 const struct ctdb_cmd *cmd;
6201 if (command == NULL) {
6202 usage_full();
6203 exit(1);
6206 cmd = match_command(command);
6207 if (cmd == NULL) {
6208 usage_full();
6209 } else {
6210 poptPrintUsage(pc, stdout, 0);
6211 printf("\nCommands:\n");
6212 printf(" %-15s %-27s %s\n",
6213 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6216 exit(1);
6219 struct poptOption cmdline_options[] = {
6220 POPT_AUTOHELP
6222 .longName = "debug",
6223 .shortName = 'd',
6224 .argInfo = POPT_ARG_STRING,
6225 .arg = &options.debuglevelstr,
6226 .val = 0,
6227 .descrip = "debug level",
6230 .longName = "timelimit",
6231 .shortName = 't',
6232 .argInfo = POPT_ARG_INT,
6233 .arg = &options.timelimit,
6234 .val = 0,
6235 .descrip = "timelimit (in seconds)",
6238 .longName = "node",
6239 .shortName = 'n',
6240 .argInfo = POPT_ARG_INT,
6241 .arg = &options.pnn,
6242 .val = 0,
6243 .descrip = "node specification - integer",
6246 .longName = NULL,
6247 .shortName = 'Y',
6248 .argInfo = POPT_ARG_NONE,
6249 .arg = &options.machinereadable,
6250 .val = 0,
6251 .descrip = "enable machine readable output",
6254 .longName = "separator",
6255 .shortName = 'x',
6256 .argInfo = POPT_ARG_STRING,
6257 .arg = &options.sep,
6258 .val = 0,
6259 .descrip = "specify separator for machine readable output",
6260 .argDescrip = "CHAR",
6263 .shortName = 'X',
6264 .argInfo = POPT_ARG_NONE,
6265 .arg = &options.machineparsable,
6266 .val = 0,
6267 .descrip = "enable machine parsable output with separator |",
6270 .longName = "verbose",
6271 .shortName = 'v',
6272 .argInfo = POPT_ARG_NONE,
6273 .arg = &options.verbose,
6274 .val = 0,
6275 .descrip = "enable verbose output",
6278 .longName = "maxruntime",
6279 .shortName = 'T',
6280 .argInfo = POPT_ARG_INT,
6281 .arg = &options.maxruntime,
6282 .val = 0,
6283 .descrip = "die if runtime exceeds this limit (in seconds)",
6285 POPT_TABLEEND
6288 static int process_command(const struct ctdb_cmd *cmd, int argc,
6289 const char **argv)
6291 TALLOC_CTX *tmp_ctx;
6292 struct ctdb_context *ctdb;
6293 const char *ctdb_socket;
6294 int ret;
6295 bool status;
6296 uint64_t srvid_offset;
6298 tmp_ctx = talloc_new(NULL);
6299 if (tmp_ctx == NULL) {
6300 fprintf(stderr, "Memory allocation error\n");
6301 goto fail;
6304 if (cmd->without_daemon) {
6305 if (options.pnn != -1) {
6306 fprintf(stderr,
6307 "Cannot specify node for command %s\n",
6308 cmd->name);
6309 goto fail;
6312 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6313 talloc_free(tmp_ctx);
6314 return ret;
6317 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6318 if (ctdb == NULL) {
6319 fprintf(stderr, "Memory allocation error\n");
6320 goto fail;
6323 ctdb->ev = tevent_context_init(ctdb);
6324 if (ctdb->ev == NULL) {
6325 fprintf(stderr, "Failed to initialize tevent\n");
6326 goto fail;
6329 ctdb_socket = path_socket(ctdb, "ctdbd");
6330 if (ctdb_socket == NULL) {
6331 fprintf(stderr, "Memory allocation error\n");
6332 goto fail;
6335 ret = ctdb_client_init(ctdb, ctdb->ev, ctdb_socket, &ctdb->client);
6336 if (ret != 0) {
6337 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6338 ctdb_socket);
6340 if (!find_node_xpnn(ctdb, NULL)) {
6341 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6343 goto fail;
6346 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6347 srvid_offset = getpid() & 0xFFFF;
6348 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6350 if (options.pnn != -1) {
6351 status = verify_pnn(ctdb, options.pnn);
6352 if (! status) {
6353 goto fail;
6356 ctdb->cmd_pnn = options.pnn;
6357 } else {
6358 ctdb->cmd_pnn = ctdb->pnn;
6361 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6362 fprintf(stderr, "Node cannot be specified for command %s\n",
6363 cmd->name);
6364 goto fail;
6367 ctdb->leader_pnn = CTDB_UNKNOWN_PNN;
6368 ret = ctdb_client_set_message_handler(ctdb->ev,
6369 ctdb->client,
6370 CTDB_SRVID_LEADER,
6371 leader_handler,
6372 ctdb);
6373 if (ret != 0) {
6374 fprintf(stderr, "Failed to setup leader handler\n");
6375 goto fail;
6378 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6379 talloc_free(tmp_ctx);
6380 return ret;
6382 fail:
6383 talloc_free(tmp_ctx);
6384 return 1;
6387 static void signal_handler(int sig)
6389 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6392 static void alarm_handler(int sig)
6394 /* Kill any child processes */
6395 signal(SIGTERM, signal_handler);
6396 kill(0, SIGTERM);
6398 _exit(1);
6401 int main(int argc, const char *argv[])
6403 int opt;
6404 const char **extra_argv;
6405 int extra_argc;
6406 const struct ctdb_cmd *cmd;
6407 const char *test_mode;
6408 int loglevel;
6409 bool ok;
6410 int ret = 0;
6412 setlinebuf(stdout);
6414 /* Set default options */
6415 options.debuglevelstr = NULL;
6416 options.timelimit = 10;
6417 options.sep = "|";
6418 options.maxruntime = 0;
6419 options.pnn = -1;
6421 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6422 POPT_CONTEXT_KEEP_FIRST);
6423 while ((opt = poptGetNextOpt(pc)) != -1) {
6424 fprintf(stderr, "Invalid option %s: %s\n",
6425 poptBadOption(pc, 0), poptStrerror(opt));
6426 exit(1);
6429 if (options.maxruntime == 0) {
6430 const char *ctdb_timeout;
6432 ctdb_timeout = getenv("CTDB_TIMEOUT");
6433 if (ctdb_timeout != NULL) {
6434 options.maxruntime = smb_strtoul(ctdb_timeout,
6435 NULL,
6437 &ret,
6438 SMB_STR_STANDARD);
6439 if (ret != 0) {
6440 fprintf(stderr, "Invalid value CTDB_TIMEOUT\n");
6441 exit(1);
6443 } else {
6444 options.maxruntime = 120;
6448 if (options.machineparsable) {
6449 options.machinereadable = 1;
6452 /* setup the remaining options for the commands */
6453 extra_argc = 0;
6454 extra_argv = poptGetArgs(pc);
6455 if (extra_argv) {
6456 extra_argv++;
6457 while (extra_argv[extra_argc]) extra_argc++;
6460 if (extra_argc < 1) {
6461 usage(NULL);
6464 cmd = match_command(extra_argv[0]);
6465 if (cmd == NULL) {
6466 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6467 exit(1);
6470 /* Enable logging */
6471 setup_logging("ctdb", DEBUG_STDERR);
6472 ok = debug_level_parse(options.debuglevelstr, &loglevel);
6473 if (!ok) {
6474 loglevel = DEBUG_ERR;
6476 debuglevel_set(loglevel);
6478 /* Stop process group kill in alarm_handler() from killing tests */
6479 test_mode = getenv("CTDB_TEST_MODE");
6480 if (test_mode != NULL) {
6481 const char *have_setpgid = getenv("CTDB_TOOL_SETPGID");
6482 if (have_setpgid == NULL) {
6483 setpgid(0, 0);
6484 setenv("CTDB_TOOL_SETPGID", "1", 1);
6488 signal(SIGALRM, alarm_handler);
6489 alarm(options.maxruntime);
6491 ret = process_command(cmd, extra_argc, extra_argv);
6492 if (ret == -1) {
6493 ret = 1;
6496 (void)poptFreeContext(pc);
6498 return ret;