ctdb-tools: Handle leader broadcasts in ctdb tool
[Samba.git] / ctdb / tools / ctdb.c
blob21221fe9212c1e4d70ecf79eaa0316c84c1c66ca
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 static struct {
56 const char *debuglevelstr;
57 int timelimit;
58 int pnn;
59 int machinereadable;
60 const char *sep;
61 int machineparsable;
62 int verbose;
63 int maxruntime;
64 int printemptyrecords;
65 int printdatasize;
66 int printlmaster;
67 int printhash;
68 int printrecordflags;
69 } options;
71 static poptContext pc;
73 struct ctdb_context {
74 struct tevent_context *ev;
75 struct ctdb_client_context *client;
76 struct ctdb_node_map *nodemap;
77 uint32_t pnn, cmd_pnn, leader_pnn;
78 uint64_t srvid;
81 static void usage(const char *command);
84 * Utility Functions
87 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
89 return (tv2->tv_sec - tv->tv_sec) +
90 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
93 static struct ctdb_node_and_flags *get_node_by_pnn(
94 struct ctdb_node_map *nodemap,
95 uint32_t pnn)
97 unsigned int i;
99 for (i=0; i<nodemap->num; i++) {
100 if (nodemap->node[i].pnn == pnn) {
101 return &nodemap->node[i];
104 return NULL;
107 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
109 static const struct {
110 uint32_t flag;
111 const char *name;
112 } flag_names[] = {
113 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
114 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
115 { NODE_FLAGS_BANNED, "BANNED" },
116 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
117 { NODE_FLAGS_DELETED, "DELETED" },
118 { NODE_FLAGS_STOPPED, "STOPPED" },
119 { NODE_FLAGS_INACTIVE, "INACTIVE" },
121 char *flags_str = NULL;
122 size_t i;
124 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
125 if (flags & flag_names[i].flag) {
126 if (flags_str == NULL) {
127 flags_str = talloc_asprintf(mem_ctx,
128 "%s", flag_names[i].name);
129 } else {
130 flags_str = talloc_asprintf_append(flags_str,
131 "|%s", flag_names[i].name);
133 if (flags_str == NULL) {
134 return "OUT-OF-MEMORY";
138 if (flags_str == NULL) {
139 return "OK";
142 return flags_str;
145 static uint64_t next_srvid(struct ctdb_context *ctdb)
147 ctdb->srvid += 1;
148 return ctdb->srvid;
152 * Get consistent nodemap information.
154 * If nodemap is already cached, use that. If not get it.
155 * If the current node is BANNED, then get nodemap from "better" node.
157 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
159 TALLOC_CTX *tmp_ctx;
160 struct ctdb_node_map *nodemap;
161 struct ctdb_node_and_flags *node;
162 uint32_t current_node;
163 int ret;
165 if (force) {
166 TALLOC_FREE(ctdb->nodemap);
169 if (ctdb->nodemap != NULL) {
170 return ctdb->nodemap;
173 tmp_ctx = talloc_new(ctdb);
174 if (tmp_ctx == NULL) {
175 return false;
178 current_node = ctdb->pnn;
179 again:
180 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
181 current_node, TIMEOUT(), &nodemap);
182 if (ret != 0) {
183 fprintf(stderr, "Failed to get nodemap from node %u\n",
184 current_node);
185 goto failed;
188 node = get_node_by_pnn(nodemap, current_node);
189 if (node->flags & NODE_FLAGS_BANNED) {
190 /* Pick next node */
191 do {
192 current_node = (current_node + 1) % nodemap->num;
193 node = get_node_by_pnn(nodemap, current_node);
194 if (! (node->flags &
195 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
196 break;
198 } while (current_node != ctdb->pnn);
200 if (current_node == ctdb->pnn) {
201 /* Tried all nodes in the cluster */
202 fprintf(stderr, "Warning: All nodes are banned.\n");
203 goto failed;
206 goto again;
209 ctdb->nodemap = talloc_steal(ctdb, nodemap);
210 return nodemap;
212 failed:
213 talloc_free(tmp_ctx);
214 return NULL;
217 static void print_pnn(uint32_t pnn)
219 if (pnn == CTDB_UNKNOWN_PNN) {
220 printf("UNKNOWN\n");
221 return;
224 printf("%u\n", pnn);
227 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
229 struct ctdb_node_map *nodemap;
230 bool found;
231 unsigned int i;
233 if (pnn == -1) {
234 return false;
237 nodemap = get_nodemap(ctdb, false);
238 if (nodemap == NULL) {
239 return false;
242 found = false;
243 for (i=0; i<nodemap->num; i++) {
244 if (nodemap->node[i].pnn == (uint32_t)pnn) {
245 found = true;
246 break;
249 if (! found) {
250 fprintf(stderr, "Node %u does not exist\n", pnn);
251 return false;
254 if (nodemap->node[i].flags &
255 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
256 fprintf(stderr, "Node %u has status %s\n", pnn,
257 pretty_print_flags(ctdb, nodemap->node[i].flags));
258 return false;
261 return true;
264 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
265 struct ctdb_node_map *nodemap)
267 struct ctdb_node_map *nodemap2;
269 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
270 if (nodemap2 == NULL) {
271 return NULL;
274 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
275 nodemap->num);
276 if (nodemap2->node == NULL) {
277 talloc_free(nodemap2);
278 return NULL;
281 return nodemap2;
285 * Get the number and the list of matching nodes
287 * nodestring := NULL | all | pnn,[pnn,...]
289 * If nodestring is NULL, use the current node.
291 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
292 const char *nodestring,
293 struct ctdb_node_map **out)
295 struct ctdb_node_map *nodemap, *nodemap2;
296 struct ctdb_node_and_flags *node;
297 unsigned int i;
299 nodemap = get_nodemap(ctdb, false);
300 if (nodemap == NULL) {
301 return false;
304 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
305 if (nodemap2 == NULL) {
306 return false;
309 if (nodestring == NULL) {
310 for (i=0; i<nodemap->num; i++) {
311 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
312 nodemap2->node[0] = nodemap->node[i];
313 break;
316 nodemap2->num = 1;
318 goto done;
321 if (strcmp(nodestring, "all") == 0) {
322 for (i=0; i<nodemap->num; i++) {
323 nodemap2->node[i] = nodemap->node[i];
325 nodemap2->num = nodemap->num;
327 goto done;
328 } else {
329 char *ns, *tok;
330 int error = 0;
332 ns = talloc_strdup(mem_ctx, nodestring);
333 if (ns == NULL) {
334 return false;
337 tok = strtok(ns, ",");
338 while (tok != NULL) {
339 uint32_t pnn;
341 pnn = (uint32_t)smb_strtoul(tok,
342 NULL,
344 &error,
345 SMB_STR_STANDARD);
346 if (error != 0) {
347 fprintf(stderr, "Invalid node %s\n", tok);
348 return false;
351 node = get_node_by_pnn(nodemap, pnn);
352 if (node == NULL) {
353 fprintf(stderr, "Node %u does not exist\n",
354 pnn);
355 return false;
358 nodemap2->node[nodemap2->num] = *node;
359 nodemap2->num += 1;
361 tok = strtok(NULL, ",");
365 done:
366 *out = nodemap2;
367 return true;
370 /* Compare IP address */
371 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
373 bool ret = false;
375 if (ip1->sa.sa_family != ip2->sa.sa_family) {
376 return false;
379 switch (ip1->sa.sa_family) {
380 case AF_INET:
381 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
382 sizeof(struct in_addr)) == 0);
383 break;
385 case AF_INET6:
386 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
387 sizeof(struct in6_addr)) == 0);
388 break;
391 return ret;
394 /* Append a node to a node map with given address and flags */
395 static bool node_map_add(struct ctdb_node_map *nodemap,
396 const char *nstr, uint32_t flags)
398 ctdb_sock_addr addr;
399 uint32_t num;
400 struct ctdb_node_and_flags *n;
401 int ret;
403 ret = ctdb_sock_addr_from_string(nstr, &addr, false);
404 if (ret != 0) {
405 fprintf(stderr, "Invalid IP address %s\n", nstr);
406 return false;
409 num = nodemap->num;
410 nodemap->node = talloc_realloc(nodemap, nodemap->node,
411 struct ctdb_node_and_flags, num+1);
412 if (nodemap->node == NULL) {
413 return false;
416 n = &nodemap->node[num];
417 n->addr = addr;
418 n->pnn = num;
419 n->flags = flags;
421 nodemap->num = num+1;
422 return true;
425 /* Read a nodes file into a node map */
426 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
427 const char *nlist)
429 char **lines;
430 int nlines;
431 int i;
432 struct ctdb_node_map *nodemap;
434 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
435 if (nodemap == NULL) {
436 return NULL;
439 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
440 if (lines == NULL) {
441 return NULL;
444 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
445 nlines--;
448 for (i=0; i<nlines; i++) {
449 char *node;
450 uint32_t flags;
451 size_t len;
453 node = lines[i];
454 /* strip leading spaces */
455 while((*node == ' ') || (*node == '\t')) {
456 node++;
459 len = strlen(node);
461 /* strip trailing spaces */
462 while ((len > 1) &&
463 ((node[len-1] == ' ') || (node[len-1] == '\t')))
465 node[len-1] = '\0';
466 len--;
469 if (len == 0) {
470 continue;
472 if (*node == '#') {
473 /* A "deleted" node is a node that is
474 commented out in the nodes file. This is
475 used instead of removing a line, which
476 would cause subsequent nodes to change
477 their PNN. */
478 flags = NODE_FLAGS_DELETED;
479 node = discard_const("0.0.0.0");
480 } else {
481 flags = 0;
483 if (! node_map_add(nodemap, node, flags)) {
484 talloc_free(lines);
485 TALLOC_FREE(nodemap);
486 return NULL;
490 talloc_free(lines);
491 return nodemap;
494 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
496 struct ctdb_node_map *nodemap;
497 const char *nodes_list = NULL;
499 const char *basedir = getenv("CTDB_BASE");
500 if (basedir == NULL) {
501 basedir = CTDB_ETCDIR;
503 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
504 if (nodes_list == NULL) {
505 fprintf(stderr, "Memory allocation error\n");
506 return NULL;
509 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
510 if (nodemap == NULL) {
511 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
512 nodes_list);
513 return NULL;
516 return nodemap;
519 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
520 struct ctdb_context *ctdb,
521 struct ctdb_dbid_map *dbmap,
522 const char *db_name)
524 struct ctdb_dbid *db = NULL;
525 const char *name;
526 unsigned int i;
527 int ret;
529 for (i=0; i<dbmap->num; i++) {
530 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
531 ctdb->pnn, TIMEOUT(),
532 dbmap->dbs[i].db_id, &name);
533 if (ret != 0) {
534 return false;
537 if (strcmp(db_name, name) == 0) {
538 talloc_free(discard_const(name));
539 db = &dbmap->dbs[i];
540 break;
544 return db;
547 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
548 const char *db_arg, uint32_t *db_id,
549 const char **db_name, uint8_t *db_flags)
551 struct ctdb_dbid_map *dbmap;
552 struct ctdb_dbid *db = NULL;
553 uint32_t id = 0;
554 const char *name = NULL;
555 unsigned int i;
556 int ret = 0;
558 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
559 ctdb->pnn, TIMEOUT(), &dbmap);
560 if (ret != 0) {
561 return false;
564 if (strncmp(db_arg, "0x", 2) == 0) {
565 id = smb_strtoul(db_arg, NULL, 0, &ret, SMB_STR_STANDARD);
566 if (ret != 0) {
567 return false;
569 for (i=0; i<dbmap->num; i++) {
570 if (id == dbmap->dbs[i].db_id) {
571 db = &dbmap->dbs[i];
572 break;
575 } else {
576 name = db_arg;
577 db = db_find(mem_ctx, ctdb, dbmap, name);
580 if (db == NULL) {
581 fprintf(stderr, "No database matching '%s' found\n", db_arg);
582 return false;
585 if (name == NULL) {
586 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
587 ctdb->pnn, TIMEOUT(), id, &name);
588 if (ret != 0) {
589 return false;
593 if (db_id != NULL) {
594 *db_id = db->db_id;
596 if (db_name != NULL) {
597 *db_name = talloc_strdup(mem_ctx, name);
599 if (db_flags != NULL) {
600 *db_flags = db->flags;
602 return true;
605 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
606 TDB_DATA *out)
608 unsigned int i;
609 TDB_DATA data;
611 if (len & 0x01) {
612 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
613 str);
614 return EINVAL;
617 data.dsize = len / 2;
618 data.dptr = talloc_size(mem_ctx, data.dsize);
619 if (data.dptr == NULL) {
620 return ENOMEM;
623 for (i=0; i<data.dsize; i++) {
624 bool ok = hex_byte(&str[i*2], &data.dptr[i]);
625 if (!ok) {
626 fprintf(stderr, "Invalid hex: %s\n", &str[i*2]);
627 return EINVAL;
631 *out = data;
632 return 0;
635 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
636 TDB_DATA *out)
638 TDB_DATA data;
639 int ret = 0;
641 if (strncmp(str, "0x", 2) == 0) {
642 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
643 if (ret != 0) {
644 return ret;
646 } else {
647 data.dptr = talloc_memdup(mem_ctx, str, len);
648 if (data.dptr == NULL) {
649 return ENOMEM;
651 data.dsize = len;
654 *out = data;
655 return 0;
658 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
659 const char *path, int argc, const char **argv)
661 pid_t pid;
662 int save_errno, status, ret;
663 const char **new_argv;
664 int i;
666 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
667 if (new_argv == NULL) {
668 return ENOMEM;
671 new_argv[0] = path;
672 for (i=0; i<argc; i++) {
673 new_argv[i+1] = argv[i];
675 new_argv[argc+1] = NULL;
677 pid = fork();
678 if (pid < 0) {
679 save_errno = errno;
680 talloc_free(new_argv);
681 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
682 command, path, strerror(save_errno));
683 return save_errno;
686 if (pid == 0) {
687 ret = execv(path, discard_const(new_argv));
688 if (ret == -1) {
689 _exit(64+errno);
691 /* Should not happen */
692 _exit(64+ENOEXEC);
695 talloc_free(new_argv);
697 ret = waitpid(pid, &status, 0);
698 if (ret == -1) {
699 save_errno = errno;
700 fprintf(stderr, "waitpid() failed for %s - %s\n",
701 command, strerror(save_errno));
702 return save_errno;
705 if (WIFEXITED(status)) {
706 int pstatus = WEXITSTATUS(status);
707 if (WIFSIGNALED(status)) {
708 fprintf(stderr, "%s terminated with signal %d\n",
709 command, WTERMSIG(status));
710 ret = EINTR;
711 } else if (pstatus >= 64 && pstatus < 255) {
712 fprintf(stderr, "%s failed with error %d\n",
713 command, pstatus-64);
714 ret = pstatus - 64;
715 } else {
716 ret = pstatus;
718 return ret;
719 } else if (WIFSIGNALED(status)) {
720 fprintf(stderr, "%s terminated with signal %d\n",
721 command, WTERMSIG(status));
722 return EINTR;
725 return 0;
728 static void leader_handler(uint64_t srvid,
729 TDB_DATA data,
730 void *private_data)
732 struct ctdb_context *ctdb = talloc_get_type_abort(
733 private_data, struct ctdb_context);
734 uint32_t leader_pnn;
735 size_t np;
736 int ret;
738 ret = ctdb_uint32_pull(data.dptr, data.dsize, &leader_pnn, &np);
739 if (ret != 0) {
740 /* Ignore packet */
741 return;
744 ctdb->leader_pnn = leader_pnn;
748 * Command Functions
751 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
752 int argc, const char **argv)
754 printf("%s\n", SAMBA_VERSION_STRING);
755 return 0;
758 static bool partially_online(TALLOC_CTX *mem_ctx,
759 struct ctdb_context *ctdb,
760 struct ctdb_node_and_flags *node)
762 struct ctdb_iface_list *iface_list;
763 unsigned int i;
764 int ret;
765 bool status = false;
767 if (node->flags != 0) {
768 return false;
771 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
772 node->pnn, TIMEOUT(), &iface_list);
773 if (ret != 0) {
774 return false;
777 status = false;
778 for (i=0; i < iface_list->num; i++) {
779 if (iface_list->iface[i].link_state == 0) {
780 status = true;
781 break;
785 return status;
788 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
789 struct ctdb_context *ctdb,
790 struct ctdb_node_map *nodemap,
791 uint32_t mypnn)
793 struct ctdb_node_and_flags *node;
794 unsigned int i;
796 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
797 options.sep,
798 "Node", options.sep,
799 "IP", options.sep,
800 "Disconnected", options.sep,
801 "Banned", options.sep,
802 "Disabled", options.sep,
803 "Unhealthy", options.sep,
804 "Stopped", options.sep,
805 "Inactive", options.sep,
806 "PartiallyOnline", options.sep,
807 "ThisNode", options.sep);
809 for (i=0; i<nodemap->num; i++) {
810 node = &nodemap->node[i];
811 if (node->flags & NODE_FLAGS_DELETED) {
812 continue;
815 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
816 options.sep,
817 node->pnn, options.sep,
818 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
819 options.sep,
820 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
821 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
822 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
823 options.sep,
824 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
825 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
826 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
827 partially_online(mem_ctx, ctdb, node), options.sep,
828 (node->pnn == mypnn)?'Y':'N', options.sep);
833 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
834 struct ctdb_node_map *nodemap, uint32_t mypnn,
835 bool print_header)
837 struct ctdb_node_and_flags *node;
838 int num_deleted_nodes = 0;
839 unsigned int i;
841 for (i=0; i<nodemap->num; i++) {
842 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
843 num_deleted_nodes++;
847 if (print_header) {
848 if (num_deleted_nodes == 0) {
849 printf("Number of nodes:%d\n", nodemap->num);
850 } else {
851 printf("Number of nodes:%d "
852 "(including %d deleted nodes)\n",
853 nodemap->num, num_deleted_nodes);
857 for (i=0; i<nodemap->num; i++) {
858 node = &nodemap->node[i];
859 if (node->flags & NODE_FLAGS_DELETED) {
860 continue;
863 printf("pnn:%u %-16s %s%s\n",
864 node->pnn,
865 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
866 partially_online(mem_ctx, ctdb, node) ?
867 "PARTIALLYONLINE" :
868 pretty_print_flags(mem_ctx, node->flags),
869 node->pnn == mypnn ? " (THIS NODE)" : "");
873 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
874 struct ctdb_node_map *nodemap, uint32_t mypnn,
875 struct ctdb_vnn_map *vnnmap, int recmode,
876 uint32_t recmaster)
878 unsigned int i;
880 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
882 if (vnnmap->generation == INVALID_GENERATION) {
883 printf("Generation:INVALID\n");
884 } else {
885 printf("Generation:%u\n", vnnmap->generation);
887 printf("Size:%d\n", vnnmap->size);
888 for (i=0; i<vnnmap->size; i++) {
889 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
892 printf("Recovery mode:%s (%d)\n",
893 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
894 recmode);
895 printf("Recovery master:");
896 print_pnn(recmaster);
899 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
900 int argc, const char **argv)
902 struct ctdb_node_map *nodemap;
903 struct ctdb_vnn_map *vnnmap;
904 int recmode;
905 uint32_t recmaster;
906 int ret;
908 if (argc != 0) {
909 usage("status");
912 nodemap = get_nodemap(ctdb, false);
913 if (nodemap == NULL) {
914 return 1;
917 if (options.machinereadable == 1) {
918 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
919 return 0;
922 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
923 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
924 if (ret != 0) {
925 return ret;
928 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
929 ctdb->cmd_pnn, TIMEOUT(), &recmode);
930 if (ret != 0) {
931 return ret;
934 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
935 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
936 if (ret != 0) {
937 return ret;
940 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
941 recmode, recmaster);
942 return 0;
945 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
946 int argc, const char **argv)
948 struct ctdb_uptime *uptime;
949 int ret, tmp, days, hours, minutes, seconds;
951 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
952 ctdb->cmd_pnn, TIMEOUT(), &uptime);
953 if (ret != 0) {
954 return ret;
957 printf("Current time of node %-4u : %s",
958 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
960 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
961 seconds = tmp % 60; tmp /= 60;
962 minutes = tmp % 60; tmp /= 60;
963 hours = tmp % 24; tmp /= 24;
964 days = tmp;
966 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
967 days, hours, minutes, seconds,
968 ctime(&uptime->ctdbd_start_time.tv_sec));
970 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
971 seconds = tmp % 60; tmp /= 60;
972 minutes = tmp % 60; tmp /= 60;
973 hours = tmp % 24; tmp /= 24;
974 days = tmp;
976 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
977 days, hours, minutes, seconds,
978 ctime(&uptime->last_recovery_finished.tv_sec));
980 printf("Duration of last recovery/failover: %lf seconds\n",
981 timeval_delta(&uptime->last_recovery_finished,
982 &uptime->last_recovery_started));
984 return 0;
987 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
988 int argc, const char **argv)
990 struct timeval tv;
991 int ret, num_clients;
993 tv = timeval_current();
994 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
995 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
996 if (ret != 0) {
997 return ret;
1000 printf("response from %u time=%.6f sec (%d clients)\n",
1001 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
1002 return 0;
1005 const char *runstate_to_string(enum ctdb_runstate runstate);
1006 enum ctdb_runstate runstate_from_string(const char *runstate_str);
1008 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1009 int argc, const char **argv)
1011 enum ctdb_runstate runstate;
1012 bool found;
1013 int ret, i;
1015 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
1016 ctdb->cmd_pnn, TIMEOUT(), &runstate);
1017 if (ret != 0) {
1018 return ret;
1021 found = true;
1022 for (i=0; i<argc; i++) {
1023 enum ctdb_runstate t;
1025 found = false;
1026 t = ctdb_runstate_from_string(argv[i]);
1027 if (t == CTDB_RUNSTATE_UNKNOWN) {
1028 printf("Invalid run state (%s)\n", argv[i]);
1029 return 1;
1032 if (t == runstate) {
1033 found = true;
1034 break;
1038 if (! found) {
1039 printf("CTDB not in required run state (got %s)\n",
1040 ctdb_runstate_to_string(runstate));
1041 return 1;
1044 printf("%s\n", ctdb_runstate_to_string(runstate));
1045 return 0;
1048 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1049 int argc, const char **argv)
1051 struct ctdb_var_list *tun_var_list;
1052 uint32_t value;
1053 int ret, i;
1054 bool found;
1056 if (argc != 1) {
1057 usage("getvar");
1060 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1061 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1062 if (ret != 0) {
1063 fprintf(stderr,
1064 "Failed to get list of variables from node %u\n",
1065 ctdb->cmd_pnn);
1066 return ret;
1069 found = false;
1070 for (i=0; i<tun_var_list->count; i++) {
1071 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1072 found = true;
1073 break;
1077 if (! found) {
1078 printf("No such tunable %s\n", argv[0]);
1079 return 1;
1082 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1083 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1084 if (ret != 0) {
1085 return ret;
1088 printf("%-26s = %u\n", argv[0], value);
1089 return 0;
1092 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1093 int argc, const char **argv)
1095 struct ctdb_var_list *tun_var_list;
1096 struct ctdb_tunable tunable;
1097 bool found;
1098 int i;
1099 int ret = 0;
1101 if (argc != 2) {
1102 usage("setvar");
1105 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1106 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1107 if (ret != 0) {
1108 fprintf(stderr,
1109 "Failed to get list of variables from node %u\n",
1110 ctdb->cmd_pnn);
1111 return ret;
1114 found = false;
1115 for (i=0; i<tun_var_list->count; i++) {
1116 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1117 found = true;
1118 break;
1122 if (! found) {
1123 printf("No such tunable %s\n", argv[0]);
1124 return 1;
1127 tunable.name = argv[0];
1128 tunable.value = smb_strtoul(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
1129 if (ret != 0) {
1130 return ret;
1133 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1134 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1135 if (ret != 0) {
1136 if (ret == 1) {
1137 fprintf(stderr,
1138 "Setting obsolete tunable variable '%s'\n",
1139 tunable.name);
1140 return 0;
1144 return ret;
1147 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1148 int argc, const char **argv)
1150 struct ctdb_var_list *tun_var_list;
1151 int ret, i;
1153 if (argc != 0) {
1154 usage("listvars");
1157 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1158 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1159 if (ret != 0) {
1160 return ret;
1163 for (i=0; i<tun_var_list->count; i++) {
1164 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1167 return 0;
1170 const struct {
1171 const char *name;
1172 uint32_t offset;
1173 } stats_fields[] = {
1174 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1175 STATISTICS_FIELD(num_clients),
1176 STATISTICS_FIELD(frozen),
1177 STATISTICS_FIELD(recovering),
1178 STATISTICS_FIELD(num_recoveries),
1179 STATISTICS_FIELD(client_packets_sent),
1180 STATISTICS_FIELD(client_packets_recv),
1181 STATISTICS_FIELD(node_packets_sent),
1182 STATISTICS_FIELD(node_packets_recv),
1183 STATISTICS_FIELD(keepalive_packets_sent),
1184 STATISTICS_FIELD(keepalive_packets_recv),
1185 STATISTICS_FIELD(node.req_call),
1186 STATISTICS_FIELD(node.reply_call),
1187 STATISTICS_FIELD(node.req_dmaster),
1188 STATISTICS_FIELD(node.reply_dmaster),
1189 STATISTICS_FIELD(node.reply_error),
1190 STATISTICS_FIELD(node.req_message),
1191 STATISTICS_FIELD(node.req_control),
1192 STATISTICS_FIELD(node.reply_control),
1193 STATISTICS_FIELD(node.req_tunnel),
1194 STATISTICS_FIELD(client.req_call),
1195 STATISTICS_FIELD(client.req_message),
1196 STATISTICS_FIELD(client.req_control),
1197 STATISTICS_FIELD(client.req_tunnel),
1198 STATISTICS_FIELD(timeouts.call),
1199 STATISTICS_FIELD(timeouts.control),
1200 STATISTICS_FIELD(timeouts.traverse),
1201 STATISTICS_FIELD(locks.num_calls),
1202 STATISTICS_FIELD(locks.num_current),
1203 STATISTICS_FIELD(locks.num_pending),
1204 STATISTICS_FIELD(locks.num_failed),
1205 STATISTICS_FIELD(total_calls),
1206 STATISTICS_FIELD(pending_calls),
1207 STATISTICS_FIELD(childwrite_calls),
1208 STATISTICS_FIELD(pending_childwrite_calls),
1209 STATISTICS_FIELD(memory_used),
1210 STATISTICS_FIELD(max_hop_count),
1211 STATISTICS_FIELD(total_ro_delegations),
1212 STATISTICS_FIELD(total_ro_revokes),
1215 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1217 static void print_statistics_machine(struct ctdb_statistics *s,
1218 bool show_header)
1220 size_t i;
1222 if (show_header) {
1223 printf("CTDB version%s", options.sep);
1224 printf("Current time of statistics%s", options.sep);
1225 printf("Statistics collected since%s", options.sep);
1226 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1227 printf("%s%s", stats_fields[i].name, options.sep);
1229 printf("num_reclock_ctdbd_latency%s", options.sep);
1230 printf("min_reclock_ctdbd_latency%s", options.sep);
1231 printf("avg_reclock_ctdbd_latency%s", options.sep);
1232 printf("max_reclock_ctdbd_latency%s", options.sep);
1234 printf("num_reclock_recd_latency%s", options.sep);
1235 printf("min_reclock_recd_latency%s", options.sep);
1236 printf("avg_reclock_recd_latency%s", options.sep);
1237 printf("max_reclock_recd_latency%s", options.sep);
1239 printf("num_call_latency%s", options.sep);
1240 printf("min_call_latency%s", options.sep);
1241 printf("avg_call_latency%s", options.sep);
1242 printf("max_call_latency%s", options.sep);
1244 printf("num_lockwait_latency%s", options.sep);
1245 printf("min_lockwait_latency%s", options.sep);
1246 printf("avg_lockwait_latency%s", options.sep);
1247 printf("max_lockwait_latency%s", options.sep);
1249 printf("num_childwrite_latency%s", options.sep);
1250 printf("min_childwrite_latency%s", options.sep);
1251 printf("avg_childwrite_latency%s", options.sep);
1252 printf("max_childwrite_latency%s", options.sep);
1253 printf("\n");
1256 printf("%u%s", CTDB_PROTOCOL, options.sep);
1257 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1258 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1259 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1260 printf("%u%s",
1261 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1262 options.sep);
1264 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1265 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1266 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1267 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1269 printf("%u%s", s->reclock.recd.num, options.sep);
1270 printf("%.6f%s", s->reclock.recd.min, options.sep);
1271 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1272 printf("%.6f%s", s->reclock.recd.max, options.sep);
1274 printf("%d%s", s->call_latency.num, options.sep);
1275 printf("%.6f%s", s->call_latency.min, options.sep);
1276 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1277 printf("%.6f%s", s->call_latency.max, options.sep);
1279 printf("%u%s", s->locks.latency.num, options.sep);
1280 printf("%.6f%s", s->locks.latency.min, options.sep);
1281 printf("%.6f%s", LATENCY_AVG(s->locks.latency), options.sep);
1282 printf("%.6f%s", s->locks.latency.max, options.sep);
1284 printf("%d%s", s->childwrite_latency.num, options.sep);
1285 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1286 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1287 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1288 printf("\n");
1291 static void print_statistics(struct ctdb_statistics *s)
1293 int tmp, days, hours, minutes, seconds;
1294 size_t i;
1295 const char *prefix = NULL;
1296 int preflen = 0;
1298 tmp = s->statistics_current_time.tv_sec -
1299 s->statistics_start_time.tv_sec;
1300 seconds = tmp % 60; tmp /= 60;
1301 minutes = tmp % 60; tmp /= 60;
1302 hours = tmp % 24; tmp /= 24;
1303 days = tmp;
1305 printf("CTDB version %u\n", CTDB_PROTOCOL);
1306 printf("Current time of statistics : %s",
1307 ctime(&s->statistics_current_time.tv_sec));
1308 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1309 days, hours, minutes, seconds,
1310 ctime(&s->statistics_start_time.tv_sec));
1312 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1313 if (strchr(stats_fields[i].name, '.') != NULL) {
1314 preflen = strcspn(stats_fields[i].name, ".") + 1;
1315 if (! prefix ||
1316 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1317 prefix = stats_fields[i].name;
1318 printf(" %*.*s\n", preflen-1, preflen-1,
1319 stats_fields[i].name);
1321 } else {
1322 preflen = 0;
1324 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1325 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1326 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1329 printf(" hop_count_buckets:");
1330 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1331 printf(" %d", s->hop_count_bucket[i]);
1333 printf("\n");
1334 printf(" lock_buckets:");
1335 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1336 printf(" %d", s->locks.buckets[i]);
1338 printf("\n");
1339 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1340 "locks_latency MIN/AVG/MAX",
1341 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1342 s->locks.latency.max, s->locks.latency.num);
1344 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1345 "reclock_ctdbd MIN/AVG/MAX",
1346 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1347 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1349 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1350 "reclock_recd MIN/AVG/MAX",
1351 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1352 s->reclock.recd.max, s->reclock.recd.num);
1354 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1355 "call_latency MIN/AVG/MAX",
1356 s->call_latency.min, LATENCY_AVG(s->call_latency),
1357 s->call_latency.max, s->call_latency.num);
1359 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1360 "childwrite_latency MIN/AVG/MAX",
1361 s->childwrite_latency.min,
1362 LATENCY_AVG(s->childwrite_latency),
1363 s->childwrite_latency.max, s->childwrite_latency.num);
1366 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1367 int argc, const char **argv)
1369 struct ctdb_statistics *stats;
1370 int ret;
1372 if (argc != 0) {
1373 usage("statistics");
1376 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1377 ctdb->cmd_pnn, TIMEOUT(), &stats);
1378 if (ret != 0) {
1379 return ret;
1382 if (options.machinereadable) {
1383 print_statistics_machine(stats, true);
1384 } else {
1385 print_statistics(stats);
1388 return 0;
1391 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1392 struct ctdb_context *ctdb,
1393 int argc, const char **argv)
1395 int ret;
1397 if (argc != 0) {
1398 usage("statisticsreset");
1401 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1402 ctdb->cmd_pnn, TIMEOUT());
1403 if (ret != 0) {
1404 return ret;
1407 return 0;
1410 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1411 int argc, const char **argv)
1413 struct ctdb_statistics_list *slist;
1414 int ret, count = 0, i;
1415 bool show_header = true;
1417 if (argc > 1) {
1418 usage("stats");
1421 if (argc == 1) {
1422 count = atoi(argv[0]);
1425 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1426 ctdb->cmd_pnn, TIMEOUT(), &slist);
1427 if (ret != 0) {
1428 return ret;
1431 for (i=0; i<slist->num; i++) {
1432 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1433 continue;
1435 if (options.machinereadable == 1) {
1436 print_statistics_machine(&slist->stats[i],
1437 show_header);
1438 show_header = false;
1439 } else {
1440 print_statistics(&slist->stats[i]);
1442 if (count > 0 && i == count) {
1443 break;
1447 return 0;
1450 static int ctdb_public_ip_cmp(const void *a, const void *b)
1452 const struct ctdb_public_ip *ip_a = a;
1453 const struct ctdb_public_ip *ip_b = b;
1455 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1458 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1459 struct ctdb_public_ip_list *ips,
1460 struct ctdb_public_ip_info **ipinfo,
1461 bool all_nodes)
1463 unsigned int i, j;
1464 char *conf, *avail, *active;
1466 if (options.machinereadable == 1) {
1467 printf("%s%s%s%s%s", options.sep,
1468 "Public IP", options.sep,
1469 "Node", options.sep);
1470 if (options.verbose == 1) {
1471 printf("%s%s%s%s%s%s\n",
1472 "ActiveInterfaces", options.sep,
1473 "AvailableInterfaces", options.sep,
1474 "ConfiguredInterfaces", options.sep);
1475 } else {
1476 printf("\n");
1478 } else {
1479 if (all_nodes) {
1480 printf("Public IPs on ALL nodes\n");
1481 } else {
1482 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1486 for (i = 0; i < ips->num; i++) {
1488 if (options.machinereadable == 1) {
1489 printf("%s%s%s%d%s", options.sep,
1490 ctdb_sock_addr_to_string(
1491 mem_ctx, &ips->ip[i].addr, false),
1492 options.sep,
1493 (int)ips->ip[i].pnn, options.sep);
1494 } else {
1495 printf("%s", ctdb_sock_addr_to_string(
1496 mem_ctx, &ips->ip[i].addr, false));
1499 if (options.verbose == 0) {
1500 if (options.machinereadable == 1) {
1501 printf("\n");
1502 } else {
1503 printf(" %d\n", (int)ips->ip[i].pnn);
1505 continue;
1508 conf = NULL;
1509 avail = NULL;
1510 active = NULL;
1512 if (ipinfo[i] == NULL) {
1513 goto skip_ipinfo;
1516 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1517 struct ctdb_iface *iface;
1519 iface = &ipinfo[i]->ifaces->iface[j];
1520 if (conf == NULL) {
1521 conf = talloc_strdup(mem_ctx, iface->name);
1522 } else {
1523 conf = talloc_asprintf_append(
1524 conf, ",%s", iface->name);
1527 if (ipinfo[i]->active_idx == j) {
1528 active = iface->name;
1531 if (iface->link_state == 0) {
1532 continue;
1535 if (avail == NULL) {
1536 avail = talloc_strdup(mem_ctx, iface->name);
1537 } else {
1538 avail = talloc_asprintf_append(
1539 avail, ",%s", iface->name);
1543 skip_ipinfo:
1545 if (options.machinereadable == 1) {
1546 printf("%s%s%s%s%s%s\n",
1547 active ? active : "", options.sep,
1548 avail ? avail : "", options.sep,
1549 conf ? conf : "", options.sep);
1550 } else {
1551 printf(" node[%d] active[%s] available[%s]"
1552 " configured[%s]\n",
1553 (int)ips->ip[i].pnn, active ? active : "",
1554 avail ? avail : "", conf ? conf : "");
1559 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1560 size_t datalen, void *private_data)
1562 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1563 private_data, struct ctdb_public_ip_list);
1564 struct ctdb_public_ip *ip;
1566 ip = (struct ctdb_public_ip *)databuf;
1567 ips->ip[ips->num] = *ip;
1568 ips->num += 1;
1570 return 0;
1573 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1574 struct ctdb_public_ip_list **out)
1576 struct ctdb_node_map *nodemap;
1577 struct ctdb_public_ip_list *ips;
1578 struct db_hash_context *ipdb;
1579 uint32_t *pnn_list;
1580 unsigned int j;
1581 int ret, count, i;
1583 nodemap = get_nodemap(ctdb, false);
1584 if (nodemap == NULL) {
1585 return 1;
1588 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1589 if (ret != 0) {
1590 goto failed;
1593 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1594 &pnn_list);
1595 if (count <= 0) {
1596 goto failed;
1599 for (i=0; i<count; i++) {
1600 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1601 pnn_list[i], TIMEOUT(),
1602 false, &ips);
1603 if (ret != 0) {
1604 goto failed;
1607 for (j=0; j<ips->num; j++) {
1608 struct ctdb_public_ip ip;
1610 ip.pnn = ips->ip[j].pnn;
1611 ip.addr = ips->ip[j].addr;
1613 if (pnn_list[i] == ip.pnn) {
1614 /* Node claims IP is hosted on it, so
1615 * save that information
1617 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1618 sizeof(ip.addr),
1619 (uint8_t *)&ip, sizeof(ip));
1620 if (ret != 0) {
1621 goto failed;
1623 } else {
1624 /* Node thinks IP is hosted elsewhere,
1625 * so overwrite with CTDB_UNKNOWN_PNN
1626 * if there's no existing entry
1628 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1629 sizeof(ip.addr));
1630 if (ret == ENOENT) {
1631 ip.pnn = CTDB_UNKNOWN_PNN;
1632 ret = db_hash_add(ipdb,
1633 (uint8_t *)&ip.addr,
1634 sizeof(ip.addr),
1635 (uint8_t *)&ip,
1636 sizeof(ip));
1637 if (ret != 0) {
1638 goto failed;
1644 TALLOC_FREE(ips);
1647 talloc_free(pnn_list);
1649 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1650 if (ret != 0) {
1651 goto failed;
1654 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1655 if (ips == NULL) {
1656 goto failed;
1659 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1660 if (ips->ip == NULL) {
1661 goto failed;
1664 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1665 if (ret != 0) {
1666 goto failed;
1669 if ((unsigned int)count != ips->num) {
1670 goto failed;
1673 talloc_free(ipdb);
1675 *out = ips;
1676 return 0;
1678 failed:
1679 talloc_free(ipdb);
1680 return 1;
1683 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1684 int argc, const char **argv)
1686 struct ctdb_public_ip_list *ips;
1687 struct ctdb_public_ip_info **ipinfo;
1688 unsigned int i;
1689 int ret;
1690 bool do_all = false;
1692 if (argc > 1) {
1693 usage("ip");
1696 if (argc == 1) {
1697 if (strcmp(argv[0], "all") == 0) {
1698 do_all = true;
1699 } else {
1700 usage("ip");
1704 if (do_all) {
1705 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1706 } else {
1707 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1708 ctdb->cmd_pnn, TIMEOUT(),
1709 false, &ips);
1711 if (ret != 0) {
1712 return ret;
1715 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1716 ctdb_public_ip_cmp);
1718 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1719 if (ipinfo == NULL) {
1720 return 1;
1723 for (i=0; i<ips->num; i++) {
1724 uint32_t pnn;
1725 if (do_all) {
1726 pnn = ips->ip[i].pnn;
1727 } else {
1728 pnn = ctdb->cmd_pnn;
1730 if (pnn == CTDB_UNKNOWN_PNN) {
1731 ipinfo[i] = NULL;
1732 continue;
1734 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1735 ctdb->client, pnn,
1736 TIMEOUT(), &ips->ip[i].addr,
1737 &ipinfo[i]);
1738 if (ret != 0) {
1739 return ret;
1743 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1744 return 0;
1747 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1748 int argc, const char **argv)
1750 struct ctdb_public_ip_info *ipinfo;
1751 ctdb_sock_addr addr;
1752 unsigned int i;
1753 int ret;
1755 if (argc != 1) {
1756 usage("ipinfo");
1759 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
1760 if (ret != 0) {
1761 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1762 return 1;
1765 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1766 ctdb->cmd_pnn, TIMEOUT(), &addr,
1767 &ipinfo);
1768 if (ret != 0) {
1769 if (ret == -1) {
1770 printf("Node %u does not know about IP %s\n",
1771 ctdb->cmd_pnn, argv[0]);
1773 return ret;
1776 printf("Public IP[%s] info on node %u\n",
1777 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1778 ctdb->cmd_pnn);
1780 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1781 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1782 ipinfo->ip.pnn, ipinfo->ifaces->num);
1784 for (i=0; i<ipinfo->ifaces->num; i++) {
1785 struct ctdb_iface *iface;
1787 iface = &ipinfo->ifaces->iface[i];
1788 iface->name[CTDB_IFACE_SIZE] = '\0';
1789 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1790 i+1, iface->name,
1791 iface->link_state == 0 ? "down" : "up",
1792 iface->references,
1793 (i == ipinfo->active_idx) ? " (active)" : "");
1796 return 0;
1799 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1800 int argc, const char **argv)
1802 struct ctdb_iface_list *ifaces;
1803 unsigned int i;
1804 int ret;
1806 if (argc != 0) {
1807 usage("ifaces");
1810 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1811 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1812 if (ret != 0) {
1813 return ret;
1816 if (ifaces->num == 0) {
1817 printf("No interfaces configured on node %u\n",
1818 ctdb->cmd_pnn);
1819 return 0;
1822 if (options.machinereadable) {
1823 printf("%s%s%s%s%s%s%s\n", options.sep,
1824 "Name", options.sep,
1825 "LinkStatus", options.sep,
1826 "References", options.sep);
1827 } else {
1828 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1831 for (i=0; i<ifaces->num; i++) {
1832 if (options.machinereadable) {
1833 printf("%s%s%s%u%s%u%s\n", options.sep,
1834 ifaces->iface[i].name, options.sep,
1835 ifaces->iface[i].link_state, options.sep,
1836 ifaces->iface[i].references, options.sep);
1837 } else {
1838 printf("name:%s link:%s references:%u\n",
1839 ifaces->iface[i].name,
1840 ifaces->iface[i].link_state ? "up" : "down",
1841 ifaces->iface[i].references);
1845 return 0;
1848 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1849 int argc, const char **argv)
1851 struct ctdb_iface_list *ifaces;
1852 struct ctdb_iface *iface;
1853 unsigned int i;
1854 int ret;
1856 if (argc != 2) {
1857 usage("setifacelink");
1860 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1861 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1862 return 1;
1865 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1866 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1867 if (ret != 0) {
1868 fprintf(stderr,
1869 "Failed to get interface information from node %u\n",
1870 ctdb->cmd_pnn);
1871 return ret;
1874 iface = NULL;
1875 for (i=0; i<ifaces->num; i++) {
1876 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1877 iface = &ifaces->iface[i];
1878 break;
1882 if (iface == NULL) {
1883 printf("Interface %s not configured on node %u\n",
1884 argv[0], ctdb->cmd_pnn);
1885 return 1;
1888 if (strcmp(argv[1], "up") == 0) {
1889 iface->link_state = 1;
1890 } else if (strcmp(argv[1], "down") == 0) {
1891 iface->link_state = 0;
1892 } else {
1893 usage("setifacelink");
1894 return 1;
1897 iface->references = 0;
1899 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1900 ctdb->cmd_pnn, TIMEOUT(), iface);
1901 if (ret != 0) {
1902 return ret;
1905 return 0;
1908 static int control_process_exists(TALLOC_CTX *mem_ctx,
1909 struct ctdb_context *ctdb,
1910 int argc, const char **argv)
1912 pid_t pid;
1913 uint64_t srvid = 0;
1914 int status;
1915 int ret = 0;
1917 if (argc != 1 && argc != 2) {
1918 usage("process-exists");
1921 pid = atoi(argv[0]);
1922 if (argc == 2) {
1923 srvid = smb_strtoull(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
1924 if (ret != 0) {
1925 return ret;
1929 if (srvid == 0) {
1930 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1931 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1932 } else {
1933 struct ctdb_pid_srvid pid_srvid;
1935 pid_srvid.pid = pid;
1936 pid_srvid.srvid = srvid;
1938 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
1939 ctdb->client, ctdb->cmd_pnn,
1940 TIMEOUT(), &pid_srvid,
1941 &status);
1944 if (ret != 0) {
1945 return ret;
1948 if (srvid == 0) {
1949 printf("PID %d %s\n", pid,
1950 (status == 0 ? "exists" : "does not exist"));
1951 } else {
1952 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
1953 (status == 0 ? "exists" : "does not exist"));
1955 return status;
1958 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1959 int argc, const char **argv)
1961 struct ctdb_dbid_map *dbmap;
1962 unsigned int i;
1963 int ret;
1965 if (argc != 0) {
1966 usage("getdbmap");
1969 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1970 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1971 if (ret != 0) {
1972 return ret;
1975 if (options.machinereadable == 1) {
1976 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1977 options.sep,
1978 "ID", options.sep,
1979 "Name", options.sep,
1980 "Path", options.sep,
1981 "Persistent", options.sep,
1982 "Sticky", options.sep,
1983 "Unhealthy", options.sep,
1984 "Readonly", options.sep,
1985 "Replicated", options.sep);
1986 } else {
1987 printf("Number of databases:%d\n", dbmap->num);
1990 for (i=0; i<dbmap->num; i++) {
1991 const char *name;
1992 const char *path;
1993 const char *health;
1994 bool persistent;
1995 bool readonly;
1996 bool sticky;
1997 bool replicated;
1998 uint32_t db_id;
2000 db_id = dbmap->dbs[i].db_id;
2002 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
2003 ctdb->cmd_pnn, TIMEOUT(), db_id,
2004 &name);
2005 if (ret != 0) {
2006 return ret;
2009 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2010 ctdb->cmd_pnn, TIMEOUT(), db_id,
2011 &path);
2012 if (ret != 0) {
2013 return ret;
2016 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2017 ctdb->cmd_pnn, TIMEOUT(), db_id,
2018 &health);
2019 if (ret != 0) {
2020 return ret;
2023 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
2024 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
2025 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
2026 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
2028 if (options.machinereadable == 1) {
2029 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2030 options.sep,
2031 db_id, options.sep,
2032 name, options.sep,
2033 path, options.sep,
2034 !! (persistent), options.sep,
2035 !! (sticky), options.sep,
2036 !! (health), options.sep,
2037 !! (readonly), options.sep,
2038 !! (replicated), options.sep);
2039 } else {
2040 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2041 db_id, name, path,
2042 persistent ? " PERSISTENT" : "",
2043 sticky ? " STICKY" : "",
2044 readonly ? " READONLY" : "",
2045 replicated ? " REPLICATED" : "",
2046 health ? " UNHEALTHY" : "");
2049 talloc_free(discard_const(name));
2050 talloc_free(discard_const(path));
2051 talloc_free(discard_const(health));
2054 return 0;
2057 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2058 int argc, const char **argv)
2060 uint32_t db_id;
2061 const char *db_name, *db_path, *db_health;
2062 uint8_t db_flags;
2063 int ret;
2065 if (argc != 1) {
2066 usage("getdbstatus");
2069 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2070 return 1;
2073 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2074 ctdb->cmd_pnn, TIMEOUT(), db_id,
2075 &db_path);
2076 if (ret != 0) {
2077 return ret;
2080 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2081 ctdb->cmd_pnn, TIMEOUT(), db_id,
2082 &db_health);
2083 if (ret != 0) {
2084 return ret;
2087 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2088 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2089 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2090 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2091 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2092 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2093 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2094 return 0;
2097 struct dump_record_state {
2098 uint32_t count;
2101 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2103 static void dump_tdb_data(const char *name, TDB_DATA val)
2105 size_t i;
2107 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2108 for (i=0; i<val.dsize; i++) {
2109 if (ISASCII(val.dptr[i])) {
2110 fprintf(stdout, "%c", val.dptr[i]);
2111 } else {
2112 fprintf(stdout, "\\%02X", val.dptr[i]);
2115 fprintf(stdout, "\"\n");
2118 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2120 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2121 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2122 fprintf(stdout, "flags: 0x%08x", header->flags);
2123 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2124 fprintf(stdout, " MIGRATED_WITH_DATA");
2126 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2127 fprintf(stdout, " VACUUM_MIGRATED");
2129 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2130 fprintf(stdout, " AUTOMATIC");
2132 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2133 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2135 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2136 fprintf(stdout, " RO_HAVE_READONLY");
2138 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2139 fprintf(stdout, " RO_REVOKING_READONLY");
2141 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2142 fprintf(stdout, " RO_REVOKE_COMPLETE");
2144 fprintf(stdout, "\n");
2148 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2149 TDB_DATA key, TDB_DATA data, void *private_data)
2151 struct dump_record_state *state =
2152 (struct dump_record_state *)private_data;
2154 state->count += 1;
2156 dump_tdb_data("key", key);
2157 dump_ltdb_header(header);
2158 dump_tdb_data("data", data);
2159 fprintf(stdout, "\n");
2161 return 0;
2164 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2165 int argc, const char **argv)
2167 struct ctdb_db_context *db;
2168 const char *db_name;
2169 uint32_t db_id;
2170 uint8_t db_flags;
2171 struct dump_record_state state;
2172 int ret;
2174 if (argc != 1) {
2175 usage("catdb");
2178 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2179 return 1;
2182 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2183 db_flags, &db);
2184 if (ret != 0) {
2185 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2186 return ret;
2189 state.count = 0;
2191 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2192 ctdb->cmd_pnn, TIMEOUT(),
2193 dump_record, &state);
2195 printf("Dumped %u records\n", state.count);
2197 return ret;
2200 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2201 int argc, const char **argv)
2203 struct ctdb_db_context *db;
2204 const char *db_name;
2205 uint32_t db_id;
2206 uint8_t db_flags;
2207 struct dump_record_state state;
2208 int ret;
2210 if (argc != 1) {
2211 usage("cattdb");
2214 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2215 return 1;
2218 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2219 db_flags, &db);
2220 if (ret != 0) {
2221 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2222 return ret;
2225 state.count = 0;
2226 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2228 printf("Dumped %u record(s)\n", state.count);
2230 return ret;
2233 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2234 struct ctdb_context *ctdb,
2235 int argc, const char **argv)
2237 uint32_t caps;
2238 int ret;
2240 if (argc != 0) {
2241 usage("getcapabilities");
2244 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2245 ctdb->cmd_pnn, TIMEOUT(), &caps);
2246 if (ret != 0) {
2247 return ret;
2250 if (options.machinereadable == 1) {
2251 printf("%s%s%s%s%s\n",
2252 options.sep,
2253 "RECMASTER", options.sep,
2254 "LMASTER", options.sep);
2255 printf("%s%d%s%d%s\n", options.sep,
2256 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2257 !! (caps & CTDB_CAP_LMASTER), options.sep);
2258 } else {
2259 printf("RECMASTER: %s\n",
2260 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2261 printf("LMASTER: %s\n",
2262 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2265 return 0;
2268 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2269 int argc, const char **argv)
2271 printf("%u\n", ctdb_client_pnn(ctdb->client));
2272 return 0;
2275 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2276 int argc, const char **argv)
2278 char *t, *lvs_helper = NULL;
2280 if (argc != 1) {
2281 usage("lvs");
2284 t = getenv("CTDB_LVS_HELPER");
2285 if (t != NULL) {
2286 lvs_helper = talloc_strdup(mem_ctx, t);
2287 } else {
2288 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2289 CTDB_HELPER_BINDIR);
2292 if (lvs_helper == NULL) {
2293 fprintf(stderr, "Unable to set LVS helper\n");
2294 return 1;
2297 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2300 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2301 int argc, const char **argv)
2303 int log_level;
2304 int ret;
2305 bool found;
2307 if (argc != 1) {
2308 usage("setdebug");
2311 found = debug_level_parse(argv[0], &log_level);
2312 if (! found) {
2313 fprintf(stderr,
2314 "Invalid debug level '%s'. Valid levels are:\n",
2315 argv[0]);
2316 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2317 return 1;
2320 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2321 ctdb->cmd_pnn, TIMEOUT(), log_level);
2322 if (ret != 0) {
2323 return ret;
2326 return 0;
2329 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2330 int argc, const char **argv)
2332 int loglevel;
2333 const char *log_str;
2334 int ret;
2336 if (argc != 0) {
2337 usage("getdebug");
2340 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2341 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2342 if (ret != 0) {
2343 return ret;
2346 log_str = debug_level_to_string(loglevel);
2347 printf("%s\n", log_str);
2349 return 0;
2352 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2353 int argc, const char **argv)
2355 const char *db_name;
2356 uint8_t db_flags = 0;
2357 int ret;
2359 if (argc < 1 || argc > 2) {
2360 usage("attach");
2363 db_name = argv[0];
2364 if (argc == 2) {
2365 if (strcmp(argv[1], "persistent") == 0) {
2366 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2367 } else if (strcmp(argv[1], "readonly") == 0) {
2368 db_flags = CTDB_DB_FLAGS_READONLY;
2369 } else if (strcmp(argv[1], "sticky") == 0) {
2370 db_flags = CTDB_DB_FLAGS_STICKY;
2371 } else if (strcmp(argv[1], "replicated") == 0) {
2372 db_flags = CTDB_DB_FLAGS_REPLICATED;
2373 } else {
2374 usage("attach");
2378 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2379 db_flags, NULL);
2380 if (ret != 0) {
2381 return ret;
2384 return 0;
2387 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2388 int argc, const char **argv)
2390 const char *db_name;
2391 uint32_t db_id;
2392 uint8_t db_flags;
2393 struct ctdb_node_map *nodemap;
2394 int recmode;
2395 unsigned int j;
2396 int ret, ret2, i;
2398 if (argc < 1) {
2399 usage("detach");
2402 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2403 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2404 if (ret != 0) {
2405 return ret;
2408 if (recmode == CTDB_RECOVERY_ACTIVE) {
2409 fprintf(stderr, "Database cannot be detached"
2410 " when recovery is active\n");
2411 return 1;
2414 nodemap = get_nodemap(ctdb, false);
2415 if (nodemap == NULL) {
2416 return 1;
2419 for (j=0; j<nodemap->num; j++) {
2420 uint32_t value;
2422 if (nodemap->node[j].flags & NODE_FLAGS_DISCONNECTED) {
2423 continue;
2425 if (nodemap->node[j].flags & NODE_FLAGS_DELETED) {
2426 continue;
2428 if (nodemap->node[j].flags & NODE_FLAGS_INACTIVE) {
2429 fprintf(stderr, "Database cannot be detached on"
2430 " inactive (stopped or banned) node %u\n",
2431 nodemap->node[j].pnn);
2432 return 1;
2435 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2436 nodemap->node[j].pnn, TIMEOUT(),
2437 "AllowClientDBAttach", &value);
2438 if (ret != 0) {
2439 fprintf(stderr,
2440 "Unable to get tunable AllowClientDBAttach"
2441 " from node %u\n", nodemap->node[j].pnn);
2442 return ret;
2445 if (value == 1) {
2446 fprintf(stderr,
2447 "Database access is still active on node %u."
2448 " Set AllowclientDBAttach=0 on all nodes.\n",
2449 nodemap->node[j].pnn);
2450 return 1;
2454 ret2 = 0;
2455 for (i=0; i<argc; i++) {
2456 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2457 &db_flags)) {
2458 continue;
2461 if (db_flags &
2462 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2463 fprintf(stderr,
2464 "Only volatile databases can be detached\n");
2465 return 1;
2468 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2469 if (ret != 0) {
2470 fprintf(stderr, "Database %s detach failed\n", db_name);
2471 ret2 = ret;
2475 return ret2;
2478 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2479 int argc, const char **argv)
2481 const char *mem_str;
2482 ssize_t n;
2483 int ret;
2485 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2486 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2487 if (ret != 0) {
2488 return ret;
2491 n = write(1, mem_str, strlen(mem_str));
2492 if (n < 0 || (size_t)n != strlen(mem_str)) {
2493 fprintf(stderr, "Failed to write talloc summary\n");
2494 return 1;
2497 return 0;
2500 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2502 bool *done = (bool *)private_data;
2503 size_t len;
2504 ssize_t n;
2506 len = strnlen((const char *)data.dptr, data.dsize);
2507 n = write(1, data.dptr, len);
2508 if (n < 0 || (size_t)n != len) {
2509 fprintf(stderr, "Failed to write talloc summary\n");
2512 *done = true;
2515 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2516 int argc, const char **argv)
2518 struct ctdb_srvid_message msg = { 0 };
2519 int ret;
2520 bool done = false;
2522 msg.pnn = ctdb->pnn;
2523 msg.srvid = next_srvid(ctdb);
2525 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2526 msg.srvid, dump_memory, &done);
2527 if (ret != 0) {
2528 return ret;
2531 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2532 ctdb->cmd_pnn, &msg);
2533 if (ret != 0) {
2534 return ret;
2537 ctdb_client_wait(ctdb->ev, &done);
2538 return 0;
2541 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2542 int argc, const char **argv)
2544 pid_t pid;
2545 int ret;
2547 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2548 ctdb->cmd_pnn, TIMEOUT(), &pid);
2549 if (ret != 0) {
2550 return ret;
2553 printf("%u\n", pid);
2554 return 0;
2557 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2558 const char *desc, uint32_t flag, bool set_flag)
2560 struct ctdb_node_map *nodemap;
2561 bool flag_is_set;
2563 nodemap = get_nodemap(ctdb, false);
2564 if (nodemap == NULL) {
2565 return 1;
2568 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2569 if (set_flag == flag_is_set) {
2570 if (set_flag) {
2571 fprintf(stderr, "Node %u is already %s\n",
2572 ctdb->cmd_pnn, desc);
2573 } else {
2574 fprintf(stderr, "Node %u is not %s\n",
2575 ctdb->cmd_pnn, desc);
2577 return 0;
2580 return 1;
2583 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2584 uint32_t flag, bool set_flag)
2586 struct ctdb_node_map *nodemap;
2587 bool flag_is_set;
2589 while (1) {
2590 nodemap = get_nodemap(ctdb, true);
2591 if (nodemap == NULL) {
2592 fprintf(stderr,
2593 "Failed to get nodemap, trying again\n");
2594 sleep(1);
2595 continue;
2598 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2599 if (flag_is_set == set_flag) {
2600 break;
2603 sleep(1);
2607 struct ipreallocate_state {
2608 int status;
2609 bool done;
2612 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2613 void *private_data)
2615 struct ipreallocate_state *state =
2616 (struct ipreallocate_state *)private_data;
2618 if (data.dsize != sizeof(int)) {
2619 /* Ignore packet */
2620 return;
2623 state->status = *(int *)data.dptr;
2624 state->done = true;
2627 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2629 struct ctdb_srvid_message msg = { 0 };
2630 struct ipreallocate_state state;
2631 int ret;
2633 msg.pnn = ctdb->pnn;
2634 msg.srvid = next_srvid(ctdb);
2636 state.done = false;
2637 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2638 msg.srvid,
2639 ipreallocate_handler, &state);
2640 if (ret != 0) {
2641 return ret;
2644 while (true) {
2645 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2646 ctdb->client,
2647 CTDB_BROADCAST_CONNECTED,
2648 &msg);
2649 if (ret != 0) {
2650 goto fail;
2653 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2654 TIMEOUT());
2655 if (ret != 0) {
2656 continue;
2659 if (state.status >= 0) {
2660 ret = 0;
2661 } else {
2662 ret = state.status;
2664 break;
2667 fail:
2668 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2669 msg.srvid, &state);
2670 return ret;
2673 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2674 int argc, const char **argv)
2676 int ret;
2678 if (argc != 0) {
2679 usage("disable");
2682 ret = check_flags(mem_ctx, ctdb, "disabled",
2683 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2684 if (ret == 0) {
2685 return 0;
2688 ret = ctdb_ctrl_disable_node(mem_ctx,
2689 ctdb->ev,
2690 ctdb->client,
2691 ctdb->cmd_pnn,
2692 TIMEOUT());
2693 if (ret != 0) {
2694 fprintf(stderr, "Failed to disable node %u\n", ctdb->cmd_pnn);
2695 return ret;
2698 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2699 return ipreallocate(mem_ctx, ctdb);
2702 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2703 int argc, const char **argv)
2705 int ret;
2707 if (argc != 0) {
2708 usage("enable");
2711 ret = check_flags(mem_ctx, ctdb, "disabled",
2712 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2713 if (ret == 0) {
2714 return 0;
2717 ret = ctdb_ctrl_enable_node(mem_ctx,
2718 ctdb->ev,
2719 ctdb->client,
2720 ctdb->cmd_pnn,
2721 TIMEOUT());
2722 if (ret != 0) {
2723 fprintf(stderr, "Failed to enable node %u\n", ctdb->cmd_pnn);
2724 return ret;
2727 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2728 return ipreallocate(mem_ctx, ctdb);
2731 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2732 int argc, const char **argv)
2734 int ret;
2736 if (argc != 0) {
2737 usage("stop");
2740 ret = check_flags(mem_ctx, ctdb, "stopped",
2741 NODE_FLAGS_STOPPED, true);
2742 if (ret == 0) {
2743 return 0;
2746 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2747 ctdb->cmd_pnn, TIMEOUT());
2748 if (ret != 0) {
2749 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2750 return ret;
2753 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2754 return ipreallocate(mem_ctx, ctdb);
2757 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2758 int argc, const char **argv)
2760 int ret;
2762 if (argc != 0) {
2763 usage("continue");
2766 ret = check_flags(mem_ctx, ctdb, "stopped",
2767 NODE_FLAGS_STOPPED, false);
2768 if (ret == 0) {
2769 return 0;
2772 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2773 ctdb->cmd_pnn, TIMEOUT());
2774 if (ret != 0) {
2775 fprintf(stderr, "Failed to continue stopped node %u\n",
2776 ctdb->cmd_pnn);
2777 return ret;
2780 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2781 return ipreallocate(mem_ctx, ctdb);
2784 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2785 int argc, const char **argv)
2787 struct ctdb_ban_state ban_state;
2788 int ret = 0;
2790 if (argc != 1) {
2791 usage("ban");
2794 ret = check_flags(mem_ctx, ctdb, "banned",
2795 NODE_FLAGS_BANNED, true);
2796 if (ret == 0) {
2797 return 0;
2800 ban_state.pnn = ctdb->cmd_pnn;
2801 ban_state.time = smb_strtoul(argv[0], NULL, 0, &ret, SMB_STR_STANDARD);
2802 if (ret != 0) {
2803 return ret;
2806 if (ban_state.time == 0) {
2807 fprintf(stderr, "Ban time cannot be zero\n");
2808 return EINVAL;
2811 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2812 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2813 if (ret != 0) {
2814 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2815 return ret;
2818 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2819 return ipreallocate(mem_ctx, ctdb);
2823 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2824 int argc, const char **argv)
2826 struct ctdb_ban_state ban_state;
2827 int ret;
2829 if (argc != 0) {
2830 usage("unban");
2833 ret = check_flags(mem_ctx, ctdb, "banned",
2834 NODE_FLAGS_BANNED, false);
2835 if (ret == 0) {
2836 return 0;
2839 ban_state.pnn = ctdb->cmd_pnn;
2840 ban_state.time = 0;
2842 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2843 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2844 if (ret != 0) {
2845 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2846 return ret;
2849 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2850 return ipreallocate(mem_ctx, ctdb);
2854 static void wait_for_shutdown(void *private_data)
2856 bool *done = (bool *)private_data;
2858 *done = true;
2861 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2862 int argc, const char **argv)
2864 int ret;
2865 bool done = false;
2867 if (argc != 0) {
2868 usage("shutdown");
2871 if (ctdb->pnn == ctdb->cmd_pnn) {
2872 ctdb_client_set_disconnect_callback(ctdb->client,
2873 wait_for_shutdown,
2874 &done);
2877 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2878 ctdb->cmd_pnn, TIMEOUT());
2879 if (ret != 0) {
2880 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2881 return ret;
2884 if (ctdb->pnn == ctdb->cmd_pnn) {
2885 ctdb_client_wait(ctdb->ev, &done);
2888 return 0;
2891 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2892 uint32_t *generation)
2894 uint32_t recmaster;
2895 int recmode;
2896 struct ctdb_vnn_map *vnnmap;
2897 int ret;
2899 again:
2900 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2901 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2902 if (ret != 0) {
2903 fprintf(stderr, "Failed to find recovery master\n");
2904 return ret;
2907 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2908 recmaster, TIMEOUT(), &recmode);
2909 if (ret != 0) {
2910 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2911 recmaster);
2912 return ret;
2915 if (recmode == CTDB_RECOVERY_ACTIVE) {
2916 sleep(1);
2917 goto again;
2920 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2921 recmaster, TIMEOUT(), &vnnmap);
2922 if (ret != 0) {
2923 fprintf(stderr, "Failed to get generation from node %u\n",
2924 recmaster);
2925 return ret;
2928 if (vnnmap->generation == INVALID_GENERATION) {
2929 talloc_free(vnnmap);
2930 sleep(1);
2931 goto again;
2934 *generation = vnnmap->generation;
2935 talloc_free(vnnmap);
2936 return 0;
2940 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2941 int argc, const char **argv)
2943 uint32_t generation, next_generation;
2944 int ret;
2946 if (argc != 0) {
2947 usage("recover");
2950 ret = get_generation(mem_ctx, ctdb, &generation);
2951 if (ret != 0) {
2952 return ret;
2955 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2956 ctdb->cmd_pnn, TIMEOUT(),
2957 CTDB_RECOVERY_ACTIVE);
2958 if (ret != 0) {
2959 fprintf(stderr, "Failed to set recovery mode active\n");
2960 return ret;
2963 while (1) {
2964 ret = get_generation(mem_ctx, ctdb, &next_generation);
2965 if (ret != 0) {
2966 fprintf(stderr,
2967 "Failed to confirm end of recovery\n");
2968 return ret;
2971 if (next_generation != generation) {
2972 break;
2975 sleep (1);
2978 return 0;
2981 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2982 int argc, const char **argv)
2984 if (argc != 0) {
2985 usage("ipreallocate");
2988 return ipreallocate(mem_ctx, ctdb);
2991 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2992 int argc, const char **argv)
2994 struct ctdb_addr_info addr_info;
2995 int ret;
2997 if (argc != 2) {
2998 usage("gratarp");
3001 ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
3002 if (ret != 0) {
3003 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3004 return 1;
3006 addr_info.iface = argv[1];
3008 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3009 ctdb->cmd_pnn, TIMEOUT(),
3010 &addr_info);
3011 if (ret != 0) {
3012 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3013 ctdb->cmd_pnn);
3014 return ret;
3017 return 0;
3020 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3021 int argc, const char **argv)
3023 ctdb_sock_addr src, dst;
3024 int ret;
3026 if (argc != 0 && argc != 2) {
3027 usage("tickle");
3030 if (argc == 0) {
3031 struct ctdb_connection_list *clist;
3032 unsigned int i;
3033 unsigned int num_failed;
3035 /* Client first but the src/dst logic is confused */
3036 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3037 if (ret != 0) {
3038 return ret;
3041 num_failed = 0;
3042 for (i = 0; i < clist->num; i++) {
3043 ret = ctdb_sys_send_tcp(&clist->conn[i].src,
3044 &clist->conn[i].dst,
3045 0, 0, 0);
3046 if (ret != 0) {
3047 num_failed += 1;
3051 TALLOC_FREE(clist);
3053 if (num_failed > 0) {
3054 fprintf(stderr, "Failed to send %d tickles\n",
3055 num_failed);
3056 return 1;
3059 return 0;
3063 ret = ctdb_sock_addr_from_string(argv[0], &src, true);
3064 if (ret != 0) {
3065 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3066 return 1;
3069 ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
3070 if (ret != 0) {
3071 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3072 return 1;
3075 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3076 if (ret != 0) {
3077 fprintf(stderr, "Failed to send tickle ack\n");
3078 return ret;
3081 return 0;
3084 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3085 int argc, const char **argv)
3087 ctdb_sock_addr addr;
3088 struct ctdb_tickle_list *tickles;
3089 unsigned port = 0;
3090 unsigned int i;
3091 int ret = 0;
3093 if (argc < 1 || argc > 2) {
3094 usage("gettickles");
3097 if (argc == 2) {
3098 port = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3099 if (ret != 0) {
3100 return ret;
3104 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3105 if (ret != 0) {
3106 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3107 return 1;
3109 ctdb_sock_addr_set_port(&addr, port);
3111 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3112 ctdb->cmd_pnn, TIMEOUT(), &addr,
3113 &tickles);
3114 if (ret != 0) {
3115 fprintf(stderr, "Failed to get list of connections\n");
3116 return ret;
3119 if (options.machinereadable) {
3120 printf("%s%s%s%s%s%s%s%s%s\n",
3121 options.sep,
3122 "Source IP", options.sep,
3123 "Port", options.sep,
3124 "Destiation IP", options.sep,
3125 "Port", options.sep);
3126 for (i=0; i<tickles->num; i++) {
3127 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3128 ctdb_sock_addr_to_string(
3129 mem_ctx, &tickles->conn[i].src, false),
3130 options.sep,
3131 ntohs(tickles->conn[i].src.ip.sin_port),
3132 options.sep,
3133 ctdb_sock_addr_to_string(
3134 mem_ctx, &tickles->conn[i].dst, false),
3135 options.sep,
3136 ntohs(tickles->conn[i].dst.ip.sin_port),
3137 options.sep);
3139 } else {
3140 printf("Connections for IP: %s\n",
3141 ctdb_sock_addr_to_string(mem_ctx,
3142 &tickles->addr, false));
3143 printf("Num connections: %u\n", tickles->num);
3144 for (i=0; i<tickles->num; i++) {
3145 printf("SRC: %s DST: %s\n",
3146 ctdb_sock_addr_to_string(
3147 mem_ctx, &tickles->conn[i].src, true),
3148 ctdb_sock_addr_to_string(
3149 mem_ctx, &tickles->conn[i].dst, true));
3153 talloc_free(tickles);
3154 return 0;
3157 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3158 struct ctdb_connection *conn);
3160 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3162 struct process_clist_state {
3163 struct ctdb_connection_list *clist;
3164 int count;
3165 unsigned int num_failed, num_total;
3166 clist_reply_func reply_func;
3169 static void process_clist_done(struct tevent_req *subreq);
3171 static struct tevent_req *process_clist_send(
3172 TALLOC_CTX *mem_ctx,
3173 struct ctdb_context *ctdb,
3174 struct ctdb_connection_list *clist,
3175 clist_request_func request_func,
3176 clist_reply_func reply_func)
3178 struct tevent_req *req, *subreq;
3179 struct process_clist_state *state;
3180 struct ctdb_req_control request;
3181 unsigned int i;
3183 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3184 if (req == NULL) {
3185 return NULL;
3188 state->clist = clist;
3189 state->reply_func = reply_func;
3191 for (i = 0; i < clist->num; i++) {
3192 request_func(&request, &clist->conn[i]);
3193 subreq = ctdb_client_control_send(state, ctdb->ev,
3194 ctdb->client, ctdb->cmd_pnn,
3195 TIMEOUT(), &request);
3196 if (tevent_req_nomem(subreq, req)) {
3197 return tevent_req_post(req, ctdb->ev);
3199 tevent_req_set_callback(subreq, process_clist_done, req);
3202 return req;
3205 static void process_clist_done(struct tevent_req *subreq)
3207 struct tevent_req *req = tevent_req_callback_data(
3208 subreq, struct tevent_req);
3209 struct process_clist_state *state = tevent_req_data(
3210 req, struct process_clist_state);
3211 struct ctdb_reply_control *reply;
3212 int ret;
3213 bool status;
3215 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3216 TALLOC_FREE(subreq);
3217 if (! status) {
3218 state->num_failed += 1;
3219 goto done;
3222 ret = state->reply_func(reply);
3223 if (ret != 0) {
3224 state->num_failed += 1;
3225 goto done;
3228 done:
3229 state->num_total += 1;
3230 if (state->num_total == state->clist->num) {
3231 tevent_req_done(req);
3235 static int process_clist_recv(struct tevent_req *req)
3237 struct process_clist_state *state = tevent_req_data(
3238 req, struct process_clist_state);
3240 return state->num_failed;
3243 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3244 int argc, const char **argv)
3246 struct ctdb_connection conn;
3247 int ret;
3249 if (argc != 0 && argc != 2) {
3250 usage("addtickle");
3253 if (argc == 0) {
3254 struct ctdb_connection_list *clist;
3255 struct tevent_req *req;
3257 /* Client first but the src/dst logic is confused */
3258 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3259 if (ret != 0) {
3260 return ret;
3262 if (clist->num == 0) {
3263 return 0;
3266 req = process_clist_send(mem_ctx, ctdb, clist,
3267 ctdb_req_control_tcp_add_delayed_update,
3268 ctdb_reply_control_tcp_add_delayed_update);
3269 if (req == NULL) {
3270 talloc_free(clist);
3271 return ENOMEM;
3274 tevent_req_poll(req, ctdb->ev);
3275 talloc_free(clist);
3277 ret = process_clist_recv(req);
3278 if (ret != 0) {
3279 fprintf(stderr, "Failed to add %d tickles\n", ret);
3280 return 1;
3283 return 0;
3286 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3287 if (ret != 0) {
3288 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3289 return 1;
3291 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3292 if (ret != 0) {
3293 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3294 return 1;
3297 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3298 ctdb->client, ctdb->cmd_pnn,
3299 TIMEOUT(), &conn);
3300 if (ret != 0) {
3301 fprintf(stderr, "Failed to register connection\n");
3302 return ret;
3305 return 0;
3308 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3309 int argc, const char **argv)
3311 struct ctdb_connection conn;
3312 int ret;
3314 if (argc != 0 && argc != 2) {
3315 usage("deltickle");
3318 if (argc == 0) {
3319 struct ctdb_connection_list *clist;
3320 struct tevent_req *req;
3322 /* Client first but the src/dst logic is confused */
3323 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3324 if (ret != 0) {
3325 return ret;
3327 if (clist->num == 0) {
3328 return 0;
3331 req = process_clist_send(mem_ctx, ctdb, clist,
3332 ctdb_req_control_tcp_remove,
3333 ctdb_reply_control_tcp_remove);
3334 if (req == NULL) {
3335 talloc_free(clist);
3336 return ENOMEM;
3339 tevent_req_poll(req, ctdb->ev);
3340 talloc_free(clist);
3342 ret = process_clist_recv(req);
3343 if (ret != 0) {
3344 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3345 return 1;
3348 return 0;
3351 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3352 if (ret != 0) {
3353 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3354 return 1;
3356 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3357 if (ret != 0) {
3358 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3359 return 1;
3362 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3363 ctdb->cmd_pnn, TIMEOUT(), &conn);
3364 if (ret != 0) {
3365 fprintf(stderr, "Failed to unregister connection\n");
3366 return ret;
3369 return 0;
3372 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3373 int argc, const char **argv)
3375 struct ctdb_node_map *nodemap;
3376 unsigned int i;
3378 if (argc != 0) {
3379 usage("listnodes");
3382 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3383 if (nodemap == NULL) {
3384 return 1;
3387 for (i=0; i<nodemap->num; i++) {
3388 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3389 continue;
3392 if (options.machinereadable) {
3393 printf("%s%u%s%s%s\n", options.sep,
3394 nodemap->node[i].pnn, options.sep,
3395 ctdb_sock_addr_to_string(
3396 mem_ctx, &nodemap->node[i].addr, false),
3397 options.sep);
3398 } else {
3399 printf("%s\n",
3400 ctdb_sock_addr_to_string(
3401 mem_ctx, &nodemap->node[i].addr, false));
3405 return 0;
3408 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3409 struct ctdb_node_map *nodemap2)
3411 unsigned int i;
3413 if (nodemap1->num != nodemap2->num) {
3414 return false;
3417 for (i=0; i<nodemap1->num; i++) {
3418 struct ctdb_node_and_flags *n1, *n2;
3420 n1 = &nodemap1->node[i];
3421 n2 = &nodemap2->node[i];
3423 if ((n1->pnn != n2->pnn) ||
3424 (n1->flags != n2->flags) ||
3425 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3426 return false;
3430 return true;
3433 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3434 struct ctdb_node_map *nm,
3435 struct ctdb_node_map *fnm,
3436 bool *reload)
3438 unsigned int i;
3439 bool check_failed = false;
3441 *reload = false;
3443 for (i=0; i<nm->num; i++) {
3444 if (i >= fnm->num) {
3445 fprintf(stderr,
3446 "Node %u (%s) missing from nodes file\n",
3447 nm->node[i].pnn,
3448 ctdb_sock_addr_to_string(
3449 mem_ctx, &nm->node[i].addr, false));
3450 check_failed = true;
3451 continue;
3453 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3454 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3455 /* Node remains deleted */
3456 continue;
3459 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3460 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3461 /* Node not newly nor previously deleted */
3462 if (! ctdb_same_ip(&nm->node[i].addr,
3463 &fnm->node[i].addr)) {
3464 fprintf(stderr,
3465 "Node %u has changed IP address"
3466 " (was %s, now %s)\n",
3467 nm->node[i].pnn,
3468 ctdb_sock_addr_to_string(
3469 mem_ctx,
3470 &nm->node[i].addr, false),
3471 ctdb_sock_addr_to_string(
3472 mem_ctx,
3473 &fnm->node[i].addr, false));
3474 check_failed = true;
3475 } else {
3476 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3477 fprintf(stderr,
3478 "WARNING: Node %u is disconnected."
3479 " You MUST fix this node manually!\n",
3480 nm->node[i].pnn);
3483 continue;
3486 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3487 /* Node is being deleted */
3488 printf("Node %u is DELETED\n", nm->node[i].pnn);
3489 *reload = true;
3490 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3491 fprintf(stderr,
3492 "ERROR: Node %u is still connected\n",
3493 nm->node[i].pnn);
3494 check_failed = true;
3496 continue;
3499 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3500 /* Node was previously deleted */
3501 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3502 *reload = true;
3506 if (check_failed) {
3507 fprintf(stderr,
3508 "ERROR: Nodes will not be reloaded due to previous error\n");
3509 return 1;
3512 /* Leftover nodes in file are NEW */
3513 for (; i < fnm->num; i++) {
3514 printf("Node %u is NEW\n", fnm->node[i].pnn);
3515 *reload = true;
3518 return 0;
3521 struct disable_recoveries_state {
3522 uint32_t *pnn_list;
3523 unsigned int node_count;
3524 bool *reply;
3525 int status;
3526 bool done;
3529 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3530 void *private_data)
3532 struct disable_recoveries_state *state =
3533 (struct disable_recoveries_state *)private_data;
3534 unsigned int i;
3535 int ret;
3537 if (data.dsize != sizeof(int)) {
3538 /* Ignore packet */
3539 return;
3542 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3543 ret = *(int *)data.dptr;
3544 if (ret < 0) {
3545 state->status = ret;
3546 state->done = true;
3547 return;
3549 for (i=0; i<state->node_count; i++) {
3550 if (state->pnn_list[i] == (uint32_t)ret) {
3551 state->reply[i] = true;
3552 break;
3556 state->done = true;
3557 for (i=0; i<state->node_count; i++) {
3558 if (! state->reply[i]) {
3559 state->done = false;
3560 break;
3565 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3566 uint32_t timeout, uint32_t *pnn_list, int count)
3568 struct ctdb_disable_message disable = { 0 };
3569 struct disable_recoveries_state state;
3570 int ret, i;
3572 disable.pnn = ctdb->pnn;
3573 disable.srvid = next_srvid(ctdb);
3574 disable.timeout = timeout;
3576 state.pnn_list = pnn_list;
3577 state.node_count = count;
3578 state.done = false;
3579 state.status = 0;
3580 state.reply = talloc_zero_array(mem_ctx, bool, count);
3581 if (state.reply == NULL) {
3582 return ENOMEM;
3585 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3586 disable.srvid,
3587 disable_recoveries_handler,
3588 &state);
3589 if (ret != 0) {
3590 return ret;
3593 for (i=0; i<count; i++) {
3594 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3595 ctdb->client,
3596 pnn_list[i],
3597 &disable);
3598 if (ret != 0) {
3599 goto fail;
3603 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3604 if (ret == ETIME) {
3605 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3606 } else {
3607 ret = (state.status >= 0 ? 0 : 1);
3610 fail:
3611 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3612 disable.srvid, &state);
3613 return ret;
3616 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3617 int argc, const char **argv)
3619 struct ctdb_node_map *nodemap = NULL;
3620 struct ctdb_node_map *file_nodemap;
3621 struct ctdb_node_map *remote_nodemap;
3622 struct ctdb_req_control request;
3623 struct ctdb_reply_control **reply;
3624 bool reload;
3625 unsigned int i;
3626 int count;
3627 int ret;
3628 uint32_t *pnn_list;
3630 nodemap = get_nodemap(ctdb, false);
3631 if (nodemap == NULL) {
3632 return 1;
3635 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3636 if (file_nodemap == NULL) {
3637 return 1;
3640 for (i=0; i<nodemap->num; i++) {
3641 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3642 continue;
3645 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3646 nodemap->node[i].pnn, TIMEOUT(),
3647 &remote_nodemap);
3648 if (ret != 0) {
3649 fprintf(stderr,
3650 "ERROR: Failed to get nodes file from node %u\n",
3651 nodemap->node[i].pnn);
3652 return ret;
3655 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3656 fprintf(stderr,
3657 "ERROR: Nodes file on node %u differs"
3658 " from current node (%u)\n",
3659 nodemap->node[i].pnn, ctdb->pnn);
3660 return 1;
3664 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3665 if (ret != 0) {
3666 return ret;
3669 if (! reload) {
3670 fprintf(stderr, "No change in nodes file,"
3671 " skipping unnecessary reload\n");
3672 return 0;
3675 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3676 mem_ctx, &pnn_list);
3677 if (count <= 0) {
3678 fprintf(stderr, "Memory allocation error\n");
3679 return 1;
3682 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3683 pnn_list, count);
3684 if (ret != 0) {
3685 fprintf(stderr, "Failed to disable recoveries\n");
3686 return ret;
3689 ctdb_req_control_reload_nodes_file(&request);
3690 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3691 pnn_list, count, TIMEOUT(),
3692 &request, NULL, &reply);
3693 if (ret != 0) {
3694 bool failed = false;
3695 int j;
3697 for (j=0; j<count; j++) {
3698 ret = ctdb_reply_control_reload_nodes_file(reply[j]);
3699 if (ret != 0) {
3700 fprintf(stderr,
3701 "Node %u failed to reload nodes\n",
3702 pnn_list[j]);
3703 failed = true;
3706 if (failed) {
3707 fprintf(stderr,
3708 "You MUST fix failed nodes manually!\n");
3712 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3713 if (ret != 0) {
3714 fprintf(stderr, "Failed to enable recoveries\n");
3715 return ret;
3718 return 0;
3721 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3722 ctdb_sock_addr *addr, uint32_t pnn)
3724 struct ctdb_public_ip_list *pubip_list;
3725 struct ctdb_public_ip pubip;
3726 struct ctdb_node_map *nodemap;
3727 struct ctdb_req_control request;
3728 uint32_t *pnn_list;
3729 unsigned int i;
3730 int ret, count;
3732 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3733 CTDB_BROADCAST_CONNECTED,
3734 2*options.timelimit);
3735 if (ret != 0) {
3736 fprintf(stderr, "Failed to disable IP check\n");
3737 return ret;
3740 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3741 pnn, TIMEOUT(), false, &pubip_list);
3742 if (ret != 0) {
3743 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3744 pnn);
3745 return ret;
3748 for (i=0; i<pubip_list->num; i++) {
3749 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3750 break;
3754 if (i == pubip_list->num) {
3755 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3756 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3757 return 1;
3760 nodemap = get_nodemap(ctdb, false);
3761 if (nodemap == NULL) {
3762 return 1;
3765 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3766 if (count <= 0) {
3767 fprintf(stderr, "Memory allocation error\n");
3768 return 1;
3771 pubip.pnn = pnn;
3772 pubip.addr = *addr;
3773 ctdb_req_control_release_ip(&request, &pubip);
3775 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3776 pnn_list, count, TIMEOUT(),
3777 &request, NULL, NULL);
3778 if (ret != 0) {
3779 fprintf(stderr, "Failed to release IP on nodes\n");
3780 return ret;
3783 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3784 pnn, TIMEOUT(), &pubip);
3785 if (ret != 0) {
3786 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3787 return ret;
3790 return 0;
3793 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3794 int argc, const char **argv)
3796 ctdb_sock_addr addr;
3797 uint32_t pnn;
3798 int retries = 0;
3799 int ret = 0;
3801 if (argc != 2) {
3802 usage("moveip");
3805 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3806 if (ret != 0) {
3807 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3808 return 1;
3811 pnn = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3812 if (pnn == CTDB_UNKNOWN_PNN || ret != 0) {
3813 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3814 return 1;
3817 while (retries < 5) {
3818 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3819 if (ret == 0) {
3820 break;
3823 sleep(3);
3824 retries++;
3827 if (ret != 0) {
3828 fprintf(stderr, "Failed to move IP %s to node %u\n",
3829 argv[0], pnn);
3830 return ret;
3833 return 0;
3836 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3837 uint32_t pnn)
3839 int ret;
3841 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3842 CTDB_BROADCAST_CONNECTED, pnn);
3843 if (ret != 0) {
3844 fprintf(stderr,
3845 "Failed to ask recovery master to distribute IPs\n");
3846 return ret;
3849 return 0;
3852 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3853 int argc, const char **argv)
3855 ctdb_sock_addr addr;
3856 struct ctdb_public_ip_list *pubip_list;
3857 struct ctdb_addr_info addr_info;
3858 unsigned int mask, i;
3859 int ret, retries = 0;
3861 if (argc != 2) {
3862 usage("addip");
3865 ret = ctdb_sock_addr_mask_from_string(argv[0], &addr, &mask);
3866 if (ret != 0) {
3867 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3868 return 1;
3871 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3872 ctdb->cmd_pnn, TIMEOUT(),
3873 false, &pubip_list);
3874 if (ret != 0) {
3875 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3876 ctdb->cmd_pnn);
3877 return 1;
3880 for (i=0; i<pubip_list->num; i++) {
3881 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3882 fprintf(stderr, "Node already knows about IP %s\n",
3883 ctdb_sock_addr_to_string(mem_ctx,
3884 &addr, false));
3885 return 0;
3889 addr_info.addr = addr;
3890 addr_info.mask = mask;
3891 addr_info.iface = argv[1];
3893 while (retries < 5) {
3894 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3895 ctdb->cmd_pnn, TIMEOUT(),
3896 &addr_info);
3897 if (ret == 0) {
3898 break;
3901 sleep(3);
3902 retries++;
3905 if (ret != 0) {
3906 fprintf(stderr, "Failed to add public IP to node %u."
3907 " Giving up\n", ctdb->cmd_pnn);
3908 return ret;
3911 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3912 if (ret != 0) {
3913 return ret;
3916 return 0;
3919 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3920 int argc, const char **argv)
3922 ctdb_sock_addr addr;
3923 struct ctdb_public_ip_list *pubip_list;
3924 struct ctdb_addr_info addr_info;
3925 unsigned int i;
3926 int ret;
3928 if (argc != 1) {
3929 usage("delip");
3932 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3933 if (ret != 0) {
3934 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3935 return 1;
3938 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3939 ctdb->cmd_pnn, TIMEOUT(),
3940 false, &pubip_list);
3941 if (ret != 0) {
3942 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3943 ctdb->cmd_pnn);
3944 return 1;
3947 for (i=0; i<pubip_list->num; i++) {
3948 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3949 break;
3953 if (i == pubip_list->num) {
3954 fprintf(stderr, "Node does not know about IP address %s\n",
3955 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
3956 return 0;
3959 addr_info.addr = addr;
3960 addr_info.mask = 0;
3961 addr_info.iface = NULL;
3963 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3964 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3965 if (ret != 0) {
3966 fprintf(stderr, "Failed to delete public IP from node %u\n",
3967 ctdb->cmd_pnn);
3968 return ret;
3971 return 0;
3974 #define DB_VERSION 3
3975 #define MAX_DB_NAME 64
3976 #define MAX_REC_BUFFER_SIZE (100*1000)
3978 struct db_header {
3979 unsigned long version;
3980 time_t timestamp;
3981 unsigned long flags;
3982 unsigned long nbuf;
3983 unsigned long nrec;
3984 char name[MAX_DB_NAME];
3987 struct backup_state {
3988 TALLOC_CTX *mem_ctx;
3989 struct ctdb_rec_buffer *recbuf;
3990 uint32_t db_id;
3991 int fd;
3992 unsigned int nbuf, nrec;
3995 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
3996 TDB_DATA key, TDB_DATA data, void *private_data)
3998 struct backup_state *state = (struct backup_state *)private_data;
3999 size_t len;
4000 int ret;
4002 if (state->recbuf == NULL) {
4003 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4004 state->db_id);
4005 if (state->recbuf == NULL) {
4006 return ENOMEM;
4010 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4011 header, key, data);
4012 if (ret != 0) {
4013 return ret;
4016 len = ctdb_rec_buffer_len(state->recbuf);
4017 if (len < MAX_REC_BUFFER_SIZE) {
4018 return 0;
4021 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4022 if (ret != 0) {
4023 fprintf(stderr, "Failed to write records to backup file\n");
4024 return ret;
4027 state->nbuf += 1;
4028 state->nrec += state->recbuf->count;
4029 TALLOC_FREE(state->recbuf);
4031 return 0;
4034 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4035 int argc, const char **argv)
4037 const char *db_name;
4038 struct ctdb_db_context *db;
4039 uint32_t db_id;
4040 uint8_t db_flags;
4041 struct backup_state state;
4042 struct db_header db_hdr;
4043 int fd, ret;
4045 if (argc != 2) {
4046 usage("backupdb");
4049 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4050 return 1;
4053 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4054 db_flags, &db);
4055 if (ret != 0) {
4056 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4057 return ret;
4060 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4061 if (fd == -1) {
4062 ret = errno;
4063 fprintf(stderr, "Failed to open file %s for writing\n",
4064 argv[1]);
4065 return ret;
4068 /* Write empty header first */
4069 ZERO_STRUCT(db_hdr);
4070 ret = write(fd, &db_hdr, sizeof(struct db_header));
4071 if (ret == -1) {
4072 ret = errno;
4073 close(fd);
4074 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4075 return ret;
4078 state.mem_ctx = mem_ctx;
4079 state.recbuf = NULL;
4080 state.fd = fd;
4081 state.nbuf = 0;
4082 state.nrec = 0;
4084 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4085 if (ret != 0) {
4086 fprintf(stderr, "Failed to collect records from DB %s\n",
4087 db_name);
4088 close(fd);
4089 return ret;
4092 if (state.recbuf != NULL) {
4093 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4094 if (ret != 0) {
4095 fprintf(stderr,
4096 "Failed to write records to backup file\n");
4097 close(fd);
4098 return ret;
4101 state.nbuf += 1;
4102 state.nrec += state.recbuf->count;
4103 TALLOC_FREE(state.recbuf);
4106 db_hdr.version = DB_VERSION;
4107 db_hdr.timestamp = time(NULL);
4108 db_hdr.flags = db_flags;
4109 db_hdr.nbuf = state.nbuf;
4110 db_hdr.nrec = state.nrec;
4111 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4113 lseek(fd, 0, SEEK_SET);
4114 ret = write(fd, &db_hdr, sizeof(struct db_header));
4115 if (ret == -1) {
4116 ret = errno;
4117 close(fd);
4118 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4119 return ret;
4122 close(fd);
4123 printf("Database backed up to %s\n", argv[1]);
4124 return 0;
4127 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4128 int argc, const char **argv)
4130 const char *db_name = NULL;
4131 struct ctdb_db_context *db;
4132 struct db_header db_hdr;
4133 struct ctdb_node_map *nodemap;
4134 struct ctdb_req_control request;
4135 struct ctdb_reply_control **reply;
4136 struct ctdb_transdb wipedb;
4137 struct ctdb_pulldb_ext pulldb;
4138 struct ctdb_rec_buffer *recbuf;
4139 uint32_t generation;
4140 uint32_t *pnn_list;
4141 char timebuf[128];
4142 ssize_t n;
4143 int fd;
4144 unsigned long i, count;
4145 int ret;
4146 uint8_t db_flags;
4148 if (argc < 1 || argc > 2) {
4149 usage("restoredb");
4152 fd = open(argv[0], O_RDONLY, 0600);
4153 if (fd == -1) {
4154 ret = errno;
4155 fprintf(stderr, "Failed to open file %s for reading\n",
4156 argv[0]);
4157 return ret;
4160 if (argc == 2) {
4161 db_name = argv[1];
4164 n = read(fd, &db_hdr, sizeof(struct db_header));
4165 if (n == -1) {
4166 ret = errno;
4167 close(fd);
4168 fprintf(stderr, "Failed to read db header from file %s\n",
4169 argv[0]);
4170 return ret;
4172 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4174 if (db_hdr.version != DB_VERSION) {
4175 fprintf(stderr,
4176 "Wrong version of backup file, expected %u, got %lu\n",
4177 DB_VERSION, db_hdr.version);
4178 close(fd);
4179 return EINVAL;
4182 if (db_name == NULL) {
4183 db_name = db_hdr.name;
4186 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4187 localtime(&db_hdr.timestamp));
4188 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4190 db_flags = db_hdr.flags & 0xff;
4191 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4192 db_flags, &db);
4193 if (ret != 0) {
4194 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4195 close(fd);
4196 return ret;
4199 nodemap = get_nodemap(ctdb, false);
4200 if (nodemap == NULL) {
4201 fprintf(stderr, "Failed to get nodemap\n");
4202 close(fd);
4203 return ENOMEM;
4206 ret = get_generation(mem_ctx, ctdb, &generation);
4207 if (ret != 0) {
4208 fprintf(stderr, "Failed to get current generation\n");
4209 close(fd);
4210 return ret;
4213 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4214 &pnn_list);
4215 if (count <= 0) {
4216 close(fd);
4217 return ENOMEM;
4220 wipedb.db_id = ctdb_db_id(db);
4221 wipedb.tid = generation;
4223 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4224 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4225 ctdb->client, pnn_list, count,
4226 TIMEOUT(), &request, NULL, NULL);
4227 if (ret != 0) {
4228 goto failed;
4232 ctdb_req_control_db_transaction_start(&request, &wipedb);
4233 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4234 pnn_list, count, TIMEOUT(),
4235 &request, NULL, NULL);
4236 if (ret != 0) {
4237 goto failed;
4240 ctdb_req_control_wipe_database(&request, &wipedb);
4241 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4242 pnn_list, count, TIMEOUT(),
4243 &request, NULL, NULL);
4244 if (ret != 0) {
4245 goto failed;
4248 pulldb.db_id = ctdb_db_id(db);
4249 pulldb.lmaster = 0;
4250 pulldb.srvid = SRVID_CTDB_PUSHDB;
4252 ctdb_req_control_db_push_start(&request, &pulldb);
4253 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4254 pnn_list, count, TIMEOUT(),
4255 &request, NULL, NULL);
4256 if (ret != 0) {
4257 goto failed;
4260 for (i=0; i<db_hdr.nbuf; i++) {
4261 struct ctdb_req_message message;
4262 TDB_DATA data;
4263 size_t np;
4265 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4266 if (ret != 0) {
4267 goto failed;
4270 data.dsize = ctdb_rec_buffer_len(recbuf);
4271 data.dptr = talloc_size(mem_ctx, data.dsize);
4272 if (data.dptr == NULL) {
4273 goto failed;
4276 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4278 message.srvid = pulldb.srvid;
4279 message.data.data = data;
4281 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4282 ctdb->client,
4283 pnn_list, count,
4284 &message, NULL);
4285 if (ret != 0) {
4286 goto failed;
4289 talloc_free(recbuf);
4290 talloc_free(data.dptr);
4293 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4294 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4295 pnn_list, count, TIMEOUT(),
4296 &request, NULL, &reply);
4297 if (ret != 0) {
4298 goto failed;
4301 for (i=0; i<count; i++) {
4302 uint32_t num_records;
4304 ret = ctdb_reply_control_db_push_confirm(reply[i],
4305 &num_records);
4306 if (ret != 0) {
4307 fprintf(stderr, "Invalid response from node %u\n",
4308 pnn_list[i]);
4309 goto failed;
4312 if (num_records != db_hdr.nrec) {
4313 fprintf(stderr, "Node %u received %u of %lu records\n",
4314 pnn_list[i], num_records, db_hdr.nrec);
4315 goto failed;
4319 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4320 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4321 pnn_list, count, TIMEOUT(),
4322 &request, NULL, NULL);
4323 if (ret != 0) {
4324 goto failed;
4327 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4328 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4329 pnn_list, count, TIMEOUT(),
4330 &request, NULL, NULL);
4331 if (ret != 0) {
4332 goto failed;
4335 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4336 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4337 ctdb->client, pnn_list, count,
4338 TIMEOUT(), &request, NULL, NULL);
4339 if (ret != 0) {
4340 goto failed;
4343 printf("Database %s restored\n", db_name);
4344 close(fd);
4345 return 0;
4348 failed:
4349 close(fd);
4350 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4351 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4352 return ret;
4355 struct dumpdbbackup_state {
4356 ctdb_rec_parser_func_t parser;
4357 struct dump_record_state sub_state;
4360 static int dumpdbbackup_handler(uint32_t reqid,
4361 struct ctdb_ltdb_header *header,
4362 TDB_DATA key, TDB_DATA data,
4363 void *private_data)
4365 struct dumpdbbackup_state *state =
4366 (struct dumpdbbackup_state *)private_data;
4367 struct ctdb_ltdb_header hdr;
4368 int ret;
4370 ret = ctdb_ltdb_header_extract(&data, &hdr);
4371 if (ret != 0) {
4372 return ret;
4375 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4378 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4379 int argc, const char **argv)
4381 struct db_header db_hdr;
4382 char timebuf[128];
4383 struct dumpdbbackup_state state;
4384 ssize_t n;
4385 unsigned long i;
4386 int fd, ret;
4388 if (argc != 1) {
4389 usage("dumpbackup");
4392 fd = open(argv[0], O_RDONLY, 0600);
4393 if (fd == -1) {
4394 ret = errno;
4395 fprintf(stderr, "Failed to open file %s for reading\n",
4396 argv[0]);
4397 return ret;
4400 n = read(fd, &db_hdr, sizeof(struct db_header));
4401 if (n == -1) {
4402 ret = errno;
4403 close(fd);
4404 fprintf(stderr, "Failed to read db header from file %s\n",
4405 argv[0]);
4406 return ret;
4408 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4410 if (db_hdr.version != DB_VERSION) {
4411 fprintf(stderr,
4412 "Wrong version of backup file, expected %u, got %lu\n",
4413 DB_VERSION, db_hdr.version);
4414 close(fd);
4415 return EINVAL;
4418 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4419 localtime(&db_hdr.timestamp));
4420 printf("Dumping database %s from backup @ %s\n",
4421 db_hdr.name, timebuf);
4423 state.parser = dump_record;
4424 state.sub_state.count = 0;
4426 for (i=0; i<db_hdr.nbuf; i++) {
4427 struct ctdb_rec_buffer *recbuf;
4429 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4430 if (ret != 0) {
4431 fprintf(stderr, "Failed to read records\n");
4432 close(fd);
4433 return ret;
4436 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4437 &state);
4438 if (ret != 0) {
4439 fprintf(stderr, "Failed to dump records\n");
4440 close(fd);
4441 return ret;
4445 close(fd);
4446 printf("Dumped %u record(s)\n", state.sub_state.count);
4447 return 0;
4450 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4451 int argc, const char **argv)
4453 const char *db_name;
4454 struct ctdb_db_context *db;
4455 uint32_t db_id;
4456 uint8_t db_flags;
4457 struct ctdb_node_map *nodemap;
4458 struct ctdb_req_control request;
4459 struct ctdb_transdb wipedb;
4460 uint32_t generation;
4461 uint32_t *pnn_list;
4462 int count, ret;
4464 if (argc != 1) {
4465 usage("wipedb");
4468 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4469 return 1;
4472 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4473 db_flags, &db);
4474 if (ret != 0) {
4475 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4476 return ret;
4479 nodemap = get_nodemap(ctdb, false);
4480 if (nodemap == NULL) {
4481 fprintf(stderr, "Failed to get nodemap\n");
4482 return ENOMEM;
4485 ret = get_generation(mem_ctx, ctdb, &generation);
4486 if (ret != 0) {
4487 fprintf(stderr, "Failed to get current generation\n");
4488 return ret;
4491 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4492 &pnn_list);
4493 if (count <= 0) {
4494 return ENOMEM;
4497 ctdb_req_control_db_freeze(&request, db_id);
4498 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4499 ctdb->client, pnn_list, count,
4500 TIMEOUT(), &request, NULL, NULL);
4501 if (ret != 0) {
4502 goto failed;
4505 wipedb.db_id = db_id;
4506 wipedb.tid = generation;
4508 ctdb_req_control_db_transaction_start(&request, &wipedb);
4509 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4510 pnn_list, count, TIMEOUT(),
4511 &request, NULL, NULL);
4512 if (ret != 0) {
4513 goto failed;
4516 ctdb_req_control_wipe_database(&request, &wipedb);
4517 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4518 pnn_list, count, TIMEOUT(),
4519 &request, NULL, NULL);
4520 if (ret != 0) {
4521 goto failed;
4524 ctdb_req_control_db_set_healthy(&request, db_id);
4525 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4526 pnn_list, count, TIMEOUT(),
4527 &request, NULL, NULL);
4528 if (ret != 0) {
4529 goto failed;
4532 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4533 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4534 pnn_list, count, TIMEOUT(),
4535 &request, NULL, NULL);
4536 if (ret != 0) {
4537 goto failed;
4540 ctdb_req_control_db_thaw(&request, db_id);
4541 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4542 ctdb->client, pnn_list, count,
4543 TIMEOUT(), &request, NULL, NULL);
4544 if (ret != 0) {
4545 goto failed;
4548 printf("Database %s wiped\n", db_name);
4549 return 0;
4552 failed:
4553 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4554 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4555 return ret;
4558 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4559 int argc, const char **argv)
4561 uint32_t recmaster;
4562 int ret;
4564 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4565 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4566 if (ret != 0) {
4567 return ret;
4570 print_pnn(recmaster);
4572 return 0;
4575 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4576 int argc, const char **argv)
4578 char *t, *event_helper = NULL;
4580 t = getenv("CTDB_EVENT_HELPER");
4581 if (t != NULL) {
4582 event_helper = talloc_strdup(mem_ctx, t);
4583 } else {
4584 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb-event",
4585 CTDB_HELPER_BINDIR);
4588 if (event_helper == NULL) {
4589 fprintf(stderr, "Unable to set event daemon helper\n");
4590 return 1;
4593 return run_helper(mem_ctx, "event daemon helper", event_helper,
4594 argc, argv);
4597 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4598 int argc, const char **argv)
4600 const char *new_argv[4];
4602 if (argc > 1) {
4603 usage("scriptstatus");
4606 new_argv[0] = "status";
4607 new_argv[1] = "legacy";
4608 new_argv[2] = (argc == 0) ? "monitor" : argv[0];
4609 new_argv[3] = NULL;
4611 (void) control_event(mem_ctx, ctdb, 3, new_argv);
4612 return 0;
4615 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4616 int argc, const char **argv)
4618 char *t, *natgw_helper = NULL;
4620 if (argc != 1) {
4621 usage("natgw");
4624 t = getenv("CTDB_NATGW_HELPER");
4625 if (t != NULL) {
4626 natgw_helper = talloc_strdup(mem_ctx, t);
4627 } else {
4628 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4629 CTDB_HELPER_BINDIR);
4632 if (natgw_helper == NULL) {
4633 fprintf(stderr, "Unable to set NAT gateway helper\n");
4634 return 1;
4637 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4638 argc, argv);
4642 * Find the PNN of the current node
4643 * discover the pnn by loading the nodes file and try to bind
4644 * to all addresses one at a time until the ip address is found.
4646 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4648 struct ctdb_node_map *nodemap;
4649 unsigned int i;
4651 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4652 if (nodemap == NULL) {
4653 return false;
4656 for (i=0; i<nodemap->num; i++) {
4657 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4658 continue;
4660 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4661 if (pnn != NULL) {
4662 *pnn = nodemap->node[i].pnn;
4664 talloc_free(nodemap);
4665 return true;
4669 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4670 talloc_free(nodemap);
4671 return false;
4674 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4675 int argc, const char **argv)
4677 const char *reclock;
4678 int ret;
4680 if (argc != 0) {
4681 usage("getreclock");
4684 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4685 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4686 if (ret != 0) {
4687 return ret;
4690 if (reclock != NULL) {
4691 printf("%s\n", reclock);
4694 return 0;
4697 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4698 struct ctdb_context *ctdb,
4699 int argc, const char **argv)
4701 uint32_t lmasterrole = 0;
4702 int ret;
4704 if (argc != 1) {
4705 usage("setlmasterrole");
4708 if (strcmp(argv[0], "on") == 0) {
4709 lmasterrole = 1;
4710 } else if (strcmp(argv[0], "off") == 0) {
4711 lmasterrole = 0;
4712 } else {
4713 usage("setlmasterrole");
4716 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4717 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4718 if (ret != 0) {
4719 return ret;
4722 return 0;
4725 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4726 struct ctdb_context *ctdb,
4727 int argc, const char **argv)
4729 uint32_t recmasterrole = 0;
4730 int ret;
4732 if (argc != 1) {
4733 usage("setrecmasterrole");
4736 if (strcmp(argv[0], "on") == 0) {
4737 recmasterrole = 1;
4738 } else if (strcmp(argv[0], "off") == 0) {
4739 recmasterrole = 0;
4740 } else {
4741 usage("setrecmasterrole");
4744 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4745 ctdb->cmd_pnn, TIMEOUT(),
4746 recmasterrole);
4747 if (ret != 0) {
4748 return ret;
4751 return 0;
4754 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4755 struct ctdb_context *ctdb,
4756 int argc, const char **argv)
4758 uint32_t db_id;
4759 uint8_t db_flags;
4760 int ret;
4762 if (argc != 1) {
4763 usage("setdbreadonly");
4766 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4767 return 1;
4770 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4771 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4772 return 1;
4775 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4776 ctdb->cmd_pnn, TIMEOUT(), db_id);
4777 if (ret != 0) {
4778 return ret;
4781 return 0;
4784 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4785 int argc, const char **argv)
4787 uint32_t db_id;
4788 uint8_t db_flags;
4789 int ret;
4791 if (argc != 1) {
4792 usage("setdbsticky");
4795 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4796 return 1;
4799 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4800 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4801 return 1;
4804 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4805 ctdb->cmd_pnn, TIMEOUT(), db_id);
4806 if (ret != 0) {
4807 return ret;
4810 return 0;
4813 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4814 int argc, const char **argv)
4816 const char *db_name;
4817 struct ctdb_db_context *db;
4818 struct ctdb_transaction_handle *h;
4819 uint8_t db_flags;
4820 TDB_DATA key, data;
4821 int ret;
4823 if (argc != 2) {
4824 usage("pfetch");
4827 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4828 return 1;
4831 if (! (db_flags &
4832 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4833 fprintf(stderr, "Transactions not supported on DB %s\n",
4834 db_name);
4835 return 1;
4838 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4839 db_flags, &db);
4840 if (ret != 0) {
4841 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4842 return ret;
4845 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4846 if (ret != 0) {
4847 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4848 return ret;
4851 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4852 TIMEOUT(), db, true, &h);
4853 if (ret != 0) {
4854 fprintf(stderr, "Failed to start transaction on db %s\n",
4855 db_name);
4856 return ret;
4859 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4860 if (ret != 0) {
4861 fprintf(stderr, "Failed to read record for key %s\n",
4862 argv[1]);
4863 ctdb_transaction_cancel(h);
4864 return ret;
4867 printf("%.*s\n", (int)data.dsize, data.dptr);
4869 ctdb_transaction_cancel(h);
4870 return 0;
4873 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4874 int argc, const char **argv)
4876 const char *db_name;
4877 struct ctdb_db_context *db;
4878 struct ctdb_transaction_handle *h;
4879 uint8_t db_flags;
4880 TDB_DATA key, data;
4881 int ret;
4883 if (argc != 3) {
4884 usage("pstore");
4887 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4888 return 1;
4891 if (! (db_flags &
4892 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4893 fprintf(stderr, "Transactions not supported on DB %s\n",
4894 db_name);
4895 return 1;
4898 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4899 db_flags, &db);
4900 if (ret != 0) {
4901 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4902 return ret;
4905 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4906 if (ret != 0) {
4907 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4908 return ret;
4911 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4912 if (ret != 0) {
4913 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4914 return ret;
4917 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4918 TIMEOUT(), db, false, &h);
4919 if (ret != 0) {
4920 fprintf(stderr, "Failed to start transaction on db %s\n",
4921 db_name);
4922 return ret;
4925 ret = ctdb_transaction_store_record(h, key, data);
4926 if (ret != 0) {
4927 fprintf(stderr, "Failed to store record for key %s\n",
4928 argv[1]);
4929 ctdb_transaction_cancel(h);
4930 return ret;
4933 ret = ctdb_transaction_commit(h);
4934 if (ret != 0) {
4935 fprintf(stderr, "Failed to commit transaction on db %s\n",
4936 db_name);
4937 ctdb_transaction_cancel(h);
4938 return ret;
4941 return 0;
4944 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4945 int argc, const char **argv)
4947 const char *db_name;
4948 struct ctdb_db_context *db;
4949 struct ctdb_transaction_handle *h;
4950 uint8_t db_flags;
4951 TDB_DATA key;
4952 int ret;
4954 if (argc != 2) {
4955 usage("pdelete");
4958 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4959 return 1;
4962 if (! (db_flags &
4963 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4964 fprintf(stderr, "Transactions not supported on DB %s\n",
4965 db_name);
4966 return 1;
4969 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4970 db_flags, &db);
4971 if (ret != 0) {
4972 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4973 return ret;
4976 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4977 if (ret != 0) {
4978 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4979 return ret;
4982 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4983 TIMEOUT(), db, false, &h);
4984 if (ret != 0) {
4985 fprintf(stderr, "Failed to start transaction on db %s\n",
4986 db_name);
4987 return ret;
4990 ret = ctdb_transaction_delete_record(h, key);
4991 if (ret != 0) {
4992 fprintf(stderr, "Failed to delete record for key %s\n",
4993 argv[1]);
4994 ctdb_transaction_cancel(h);
4995 return ret;
4998 ret = ctdb_transaction_commit(h);
4999 if (ret != 0) {
5000 fprintf(stderr, "Failed to commit transaction on db %s\n",
5001 db_name);
5002 ctdb_transaction_cancel(h);
5003 return ret;
5006 return 0;
5009 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5011 const char *t;
5012 size_t n;
5013 int ret;
5015 *data = tdb_null;
5017 /* Skip whitespace */
5018 n = strspn(*ptr, " \t");
5019 t = *ptr + n;
5021 if (t[0] == '"') {
5022 /* Quoted ASCII string - no wide characters! */
5023 t++;
5024 n = strcspn(t, "\"");
5025 if (t[n] == '"') {
5026 if (n > 0) {
5027 ret = str_to_data(t, n, mem_ctx, data);
5028 if (ret != 0) {
5029 return ret;
5032 *ptr = t + n + 1;
5033 } else {
5034 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5035 return 1;
5037 } else {
5038 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5039 return 1;
5042 return 0;
5045 #define MAX_LINE_SIZE 1024
5047 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5048 TDB_DATA *key, TDB_DATA *value)
5050 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5051 const char *ptr;
5052 int ret;
5054 ptr = fgets(line, MAX_LINE_SIZE, file);
5055 if (ptr == NULL) {
5056 return false;
5059 /* Get key */
5060 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5061 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5062 /* Line Ignored but not EOF */
5063 *key = tdb_null;
5064 return true;
5067 /* Get value */
5068 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5069 if (ret != 0) {
5070 /* Line Ignored but not EOF */
5071 talloc_free(key->dptr);
5072 *key = tdb_null;
5073 return true;
5076 return true;
5079 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5080 int argc, const char **argv)
5082 const char *db_name;
5083 struct ctdb_db_context *db;
5084 struct ctdb_transaction_handle *h;
5085 uint8_t db_flags;
5086 FILE *file;
5087 TDB_DATA key = tdb_null, value = tdb_null;
5088 int ret;
5090 if (argc < 1 || argc > 2) {
5091 usage("ptrans");
5094 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5095 return 1;
5098 if (! (db_flags &
5099 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5100 fprintf(stderr, "Transactions not supported on DB %s\n",
5101 db_name);
5102 return 1;
5105 if (argc == 2) {
5106 file = fopen(argv[1], "r");
5107 if (file == NULL) {
5108 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5109 return 1;
5111 } else {
5112 file = stdin;
5115 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5116 db_flags, &db);
5117 if (ret != 0) {
5118 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5119 goto done;
5122 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5123 TIMEOUT(), db, false, &h);
5124 if (ret != 0) {
5125 fprintf(stderr, "Failed to start transaction on db %s\n",
5126 db_name);
5127 goto done;
5130 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5131 if (key.dsize != 0) {
5132 ret = ctdb_transaction_store_record(h, key, value);
5133 if (ret != 0) {
5134 fprintf(stderr, "Failed to store record\n");
5135 ctdb_transaction_cancel(h);
5136 goto done;
5138 talloc_free(key.dptr);
5139 talloc_free(value.dptr);
5143 ret = ctdb_transaction_commit(h);
5144 if (ret != 0) {
5145 fprintf(stderr, "Failed to commit transaction on db %s\n",
5146 db_name);
5147 ctdb_transaction_cancel(h);
5150 done:
5151 if (file != stdin) {
5152 fclose(file);
5154 return ret;
5157 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5158 int argc, const char **argv)
5160 struct tdb_context *tdb;
5161 TDB_DATA key, data;
5162 struct ctdb_ltdb_header header;
5163 int ret;
5165 if (argc < 2 || argc > 3) {
5166 usage("tfetch");
5169 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5170 if (tdb == NULL) {
5171 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5172 return 1;
5175 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5176 if (ret != 0) {
5177 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5178 tdb_close(tdb);
5179 return ret;
5182 data = tdb_fetch(tdb, key);
5183 if (data.dptr == NULL) {
5184 fprintf(stderr, "No record for key %s\n", argv[1]);
5185 tdb_close(tdb);
5186 return 1;
5189 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5190 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5191 tdb_close(tdb);
5192 return 1;
5195 tdb_close(tdb);
5197 if (argc == 3) {
5198 int fd;
5199 ssize_t nwritten;
5201 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5202 if (fd == -1) {
5203 fprintf(stderr, "Failed to open output file %s\n",
5204 argv[2]);
5205 goto fail;
5208 nwritten = sys_write(fd, data.dptr, data.dsize);
5209 if (nwritten == -1 ||
5210 (size_t)nwritten != data.dsize) {
5211 fprintf(stderr, "Failed to write record to file\n");
5212 close(fd);
5213 goto fail;
5216 close(fd);
5219 fail:
5220 ret = ctdb_ltdb_header_extract(&data, &header);
5221 if (ret != 0) {
5222 fprintf(stderr, "Failed to parse header from data\n");
5223 return 1;
5226 dump_ltdb_header(&header);
5227 dump_tdb_data("data", data);
5229 return 0;
5232 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5233 int argc, const char **argv)
5235 struct tdb_context *tdb;
5236 TDB_DATA key, data[2], value;
5237 struct ctdb_ltdb_header header;
5238 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5239 size_t np;
5240 int ret = 0;
5242 if (argc < 3 || argc > 5) {
5243 usage("tstore");
5246 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5247 if (tdb == NULL) {
5248 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5249 return 1;
5252 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5253 if (ret != 0) {
5254 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5255 tdb_close(tdb);
5256 return ret;
5259 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5260 if (ret != 0) {
5261 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5262 tdb_close(tdb);
5263 return ret;
5266 ZERO_STRUCT(header);
5268 if (argc > 3) {
5269 header.rsn = (uint64_t)smb_strtoull(argv[3],
5270 NULL,
5272 &ret,
5273 SMB_STR_STANDARD);
5274 if (ret != 0) {
5275 return ret;
5278 if (argc > 4) {
5279 header.dmaster = (uint32_t)atol(argv[4]);
5281 if (argc > 5) {
5282 header.flags = (uint32_t)atol(argv[5]);
5285 ctdb_ltdb_header_push(&header, header_buf, &np);
5287 data[0].dsize = np;
5288 data[0].dptr = header_buf;
5290 data[1].dsize = value.dsize;
5291 data[1].dptr = value.dptr;
5293 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5294 if (ret != 0) {
5295 fprintf(stderr, "Failed to write record %s to file %s\n",
5296 argv[1], argv[0]);
5299 tdb_close(tdb);
5301 return ret;
5304 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5305 int argc, const char **argv)
5307 const char *db_name;
5308 struct ctdb_db_context *db;
5309 struct ctdb_record_handle *h;
5310 uint8_t db_flags;
5311 TDB_DATA key, data;
5312 bool readonly = false;
5313 int ret;
5315 if (argc < 2 || argc > 3) {
5316 usage("readkey");
5319 if (argc == 3) {
5320 if (strcmp(argv[2], "readonly") == 0) {
5321 readonly = true;
5322 } else {
5323 usage("readkey");
5327 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5328 return 1;
5331 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5332 fprintf(stderr, "DB %s is not a volatile database\n",
5333 db_name);
5334 return 1;
5337 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5338 db_flags, &db);
5339 if (ret != 0) {
5340 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5341 return ret;
5344 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5345 if (ret != 0) {
5346 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5347 return ret;
5350 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5351 db, key, readonly, &h, NULL, &data);
5352 if (ret != 0) {
5353 fprintf(stderr, "Failed to read record for key %s\n",
5354 argv[1]);
5355 } else {
5356 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5357 (int)data.dsize, data.dptr);
5360 talloc_free(h);
5361 return ret;
5364 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5365 int argc, const char **argv)
5367 const char *db_name;
5368 struct ctdb_db_context *db;
5369 struct ctdb_record_handle *h;
5370 uint8_t db_flags;
5371 TDB_DATA key, data;
5372 int ret;
5374 if (argc != 3) {
5375 usage("writekey");
5378 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5379 return 1;
5382 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5383 fprintf(stderr, "DB %s is not a volatile database\n",
5384 db_name);
5385 return 1;
5388 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5389 db_flags, &db);
5390 if (ret != 0) {
5391 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5392 return ret;
5395 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5396 if (ret != 0) {
5397 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5398 return ret;
5401 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5402 if (ret != 0) {
5403 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5404 return ret;
5407 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5408 db, key, false, &h, NULL, NULL);
5409 if (ret != 0) {
5410 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5411 return ret;
5414 ret = ctdb_store_record(h, data);
5415 if (ret != 0) {
5416 fprintf(stderr, "Failed to store record for key %s\n",
5417 argv[1]);
5420 talloc_free(h);
5421 return ret;
5424 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5425 int argc, const char **argv)
5427 const char *db_name;
5428 struct ctdb_db_context *db;
5429 struct ctdb_record_handle *h;
5430 uint8_t db_flags;
5431 TDB_DATA key, data;
5432 int ret;
5434 if (argc != 2) {
5435 usage("deletekey");
5438 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5439 return 1;
5442 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5443 fprintf(stderr, "DB %s is not a volatile database\n",
5444 db_name);
5445 return 1;
5448 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5449 db_flags, &db);
5450 if (ret != 0) {
5451 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5452 return ret;
5455 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5456 if (ret != 0) {
5457 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5458 return ret;
5461 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5462 db, key, false, &h, NULL, &data);
5463 if (ret != 0) {
5464 fprintf(stderr, "Failed to fetch record for key %s\n",
5465 argv[1]);
5466 return ret;
5469 ret = ctdb_delete_record(h);
5470 if (ret != 0) {
5471 fprintf(stderr, "Failed to delete record for key %s\n",
5472 argv[1]);
5475 talloc_free(h);
5476 return ret;
5479 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5480 int argc, const char **argv)
5482 struct sockaddr_in sin;
5483 unsigned int port;
5484 int s, v;
5485 int ret;
5487 if (argc != 1) {
5488 usage("chktcpport");
5491 port = atoi(argv[0]);
5493 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5494 if (s == -1) {
5495 fprintf(stderr, "Failed to open local socket\n");
5496 return errno;
5499 v = fcntl(s, F_GETFL, 0);
5500 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5501 fprintf(stderr, "Unable to set socket non-blocking\n");
5502 close(s);
5503 return errno;
5506 bzero(&sin, sizeof(sin));
5507 sin.sin_family = AF_INET;
5508 sin.sin_port = htons(port);
5509 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5510 close(s);
5511 if (ret == -1) {
5512 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5513 return errno;
5516 return 0;
5519 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5520 int argc, const char **argv)
5522 uint32_t db_id;
5523 const char *db_name;
5524 uint64_t seqnum;
5525 int ret;
5527 if (argc != 1) {
5528 usage("getdbseqnum");
5531 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5532 return 1;
5535 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5536 ctdb->cmd_pnn, TIMEOUT(), db_id,
5537 &seqnum);
5538 if (ret != 0) {
5539 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5540 db_name);
5541 return ret;
5544 printf("0x%"PRIx64"\n", seqnum);
5545 return 0;
5548 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5549 int argc, const char **argv)
5551 const char *nodestring = NULL;
5552 struct ctdb_node_map *nodemap;
5553 unsigned int i;
5554 int ret;
5555 bool print_hdr = false;
5557 if (argc > 1) {
5558 usage("nodestatus");
5561 if (argc == 1) {
5562 nodestring = argv[0];
5563 if (strcmp(nodestring, "all") == 0) {
5564 print_hdr = true;
5568 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5569 return 1;
5572 if (options.machinereadable) {
5573 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5574 } else {
5575 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5578 ret = 0;
5579 for (i=0; i<nodemap->num; i++) {
5580 uint32_t flags = nodemap->node[i].flags;
5582 if ((flags & NODE_FLAGS_DELETED) != 0) {
5583 continue;
5586 ret |= flags;
5589 return ret;
5592 const struct {
5593 const char *name;
5594 uint32_t offset;
5595 } db_stats_fields[] = {
5596 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5597 DBSTATISTICS_FIELD(db_ro_delegations),
5598 DBSTATISTICS_FIELD(db_ro_revokes),
5599 DBSTATISTICS_FIELD(locks.num_calls),
5600 DBSTATISTICS_FIELD(locks.num_current),
5601 DBSTATISTICS_FIELD(locks.num_pending),
5602 DBSTATISTICS_FIELD(locks.num_failed),
5605 static void print_dbstatistics(const char *db_name,
5606 struct ctdb_db_statistics *s)
5608 size_t i;
5609 const char *prefix = NULL;
5610 int preflen = 0;
5612 printf("DB Statistics %s\n", db_name);
5614 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5615 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5616 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5617 if (! prefix ||
5618 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5619 prefix = db_stats_fields[i].name;
5620 printf(" %*.*s\n", preflen-1, preflen-1,
5621 db_stats_fields[i].name);
5623 } else {
5624 preflen = 0;
5626 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5627 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5628 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5631 printf(" hop_count_buckets:");
5632 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5633 printf(" %d", s->hop_count_bucket[i]);
5635 printf("\n");
5637 printf(" lock_buckets:");
5638 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5639 printf(" %d", s->locks.buckets[i]);
5641 printf("\n");
5643 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5644 "locks_latency MIN/AVG/MAX",
5645 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5646 s->locks.latency.max, s->locks.latency.num);
5648 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5649 "vacuum_latency MIN/AVG/MAX",
5650 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5651 s->vacuum.latency.max, s->vacuum.latency.num);
5653 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5654 for (i=0; i<s->num_hot_keys; i++) {
5655 size_t j;
5656 printf(" Count:%d Key:", s->hot_keys[i].count);
5657 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5658 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5660 printf("\n");
5664 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5665 int argc, const char **argv)
5667 uint32_t db_id;
5668 const char *db_name;
5669 struct ctdb_db_statistics *dbstats;
5670 int ret;
5672 if (argc != 1) {
5673 usage("dbstatistics");
5676 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5677 return 1;
5680 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5681 ctdb->cmd_pnn, TIMEOUT(), db_id,
5682 &dbstats);
5683 if (ret != 0) {
5684 fprintf(stderr, "Failed to get statistics for DB %s\n",
5685 db_name);
5686 return ret;
5689 print_dbstatistics(db_name, dbstats);
5690 return 0;
5693 struct disable_takeover_runs_state {
5694 uint32_t *pnn_list;
5695 unsigned int node_count;
5696 bool *reply;
5697 int status;
5698 bool done;
5701 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5702 void *private_data)
5704 struct disable_takeover_runs_state *state =
5705 (struct disable_takeover_runs_state *)private_data;
5706 unsigned int i;
5707 int ret;
5709 if (data.dsize != sizeof(int)) {
5710 /* Ignore packet */
5711 return;
5714 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5715 ret = *(int *)data.dptr;
5716 if (ret < 0) {
5717 state->status = ret;
5718 state->done = true;
5719 return;
5721 for (i=0; i<state->node_count; i++) {
5722 if (state->pnn_list[i] == (uint32_t)ret) {
5723 state->reply[i] = true;
5724 break;
5728 state->done = true;
5729 for (i=0; i<state->node_count; i++) {
5730 if (! state->reply[i]) {
5731 state->done = false;
5732 break;
5737 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5738 struct ctdb_context *ctdb, uint32_t timeout,
5739 uint32_t *pnn_list, int count)
5741 struct ctdb_disable_message disable = { 0 };
5742 struct disable_takeover_runs_state state;
5743 int ret, i;
5745 disable.pnn = ctdb->pnn;
5746 disable.srvid = next_srvid(ctdb);
5747 disable.timeout = timeout;
5749 state.pnn_list = pnn_list;
5750 state.node_count = count;
5751 state.done = false;
5752 state.status = 0;
5753 state.reply = talloc_zero_array(mem_ctx, bool, count);
5754 if (state.reply == NULL) {
5755 return ENOMEM;
5758 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5759 disable.srvid,
5760 disable_takeover_run_handler,
5761 &state);
5762 if (ret != 0) {
5763 return ret;
5766 for (i=0; i<count; i++) {
5767 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5768 ctdb->client,
5769 pnn_list[i],
5770 &disable);
5771 if (ret != 0) {
5772 goto fail;
5776 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5777 if (ret == ETIME) {
5778 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5779 } else {
5780 ret = (state.status >= 0 ? 0 : 1);
5783 fail:
5784 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5785 disable.srvid, &state);
5786 return ret;
5789 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5790 int argc, const char **argv)
5792 const char *nodestring = NULL;
5793 struct ctdb_node_map *nodemap, *nodemap2;
5794 struct ctdb_req_control request;
5795 uint32_t *pnn_list, *pnn_list2;
5796 int ret, count, count2;
5798 if (argc > 1) {
5799 usage("reloadips");
5802 if (argc == 1) {
5803 nodestring = argv[0];
5806 nodemap = get_nodemap(ctdb, false);
5807 if (nodemap == NULL) {
5808 return 1;
5811 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5812 return 1;
5815 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5816 mem_ctx, &pnn_list);
5817 if (count <= 0) {
5818 fprintf(stderr, "Memory allocation error\n");
5819 return 1;
5822 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5823 mem_ctx, &pnn_list2);
5824 if (count2 <= 0) {
5825 fprintf(stderr, "Memory allocation error\n");
5826 return 1;
5829 /* Disable takeover runs on all connected nodes. A reply
5830 * indicating success is needed from each node so all nodes
5831 * will need to be active.
5833 * A check could be added to not allow reloading of IPs when
5834 * there are disconnected nodes. However, this should
5835 * probably be left up to the administrator.
5837 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5838 pnn_list, count);
5839 if (ret != 0) {
5840 fprintf(stderr, "Failed to disable takeover runs\n");
5841 return ret;
5844 /* Now tell all the desired nodes to reload their public IPs.
5845 * Keep trying this until it succeeds. This assumes all
5846 * failures are transient, which might not be true...
5848 ctdb_req_control_reload_public_ips(&request);
5849 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5850 pnn_list2, count2, TIMEOUT(),
5851 &request, NULL, NULL);
5852 if (ret != 0) {
5853 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5856 /* It isn't strictly necessary to wait until takeover runs are
5857 * re-enabled but doing so can't hurt.
5859 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5860 if (ret != 0) {
5861 fprintf(stderr, "Failed to enable takeover runs\n");
5862 return ret;
5865 return ipreallocate(mem_ctx, ctdb);
5869 static const struct ctdb_cmd {
5870 const char *name;
5871 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5872 bool without_daemon; /* can be run without daemon running ? */
5873 bool remote; /* can be run on remote nodes */
5874 const char *msg;
5875 const char *args;
5876 } ctdb_commands[] = {
5877 { "version", control_version, true, false,
5878 "show version of ctdb", NULL },
5879 { "status", control_status, false, true,
5880 "show node status", NULL },
5881 { "uptime", control_uptime, false, true,
5882 "show node uptime", NULL },
5883 { "ping", control_ping, false, true,
5884 "ping a node", NULL },
5885 { "runstate", control_runstate, false, true,
5886 "get/check runstate of a node",
5887 "[setup|first_recovery|startup|running]" },
5888 { "getvar", control_getvar, false, true,
5889 "get a tunable variable", "<name>" },
5890 { "setvar", control_setvar, false, true,
5891 "set a tunable variable", "<name> <value>" },
5892 { "listvars", control_listvars, false, true,
5893 "list tunable variables", NULL },
5894 { "statistics", control_statistics, false, true,
5895 "show ctdb statistics", NULL },
5896 { "statisticsreset", control_statistics_reset, false, true,
5897 "reset ctdb statistics", NULL },
5898 { "stats", control_stats, false, true,
5899 "show rolling statistics", "[count]" },
5900 { "ip", control_ip, false, true,
5901 "show public ips", "[all]" },
5902 { "ipinfo", control_ipinfo, false, true,
5903 "show public ip details", "<ip>" },
5904 { "ifaces", control_ifaces, false, true,
5905 "show interfaces", NULL },
5906 { "setifacelink", control_setifacelink, false, true,
5907 "set interface link status", "<iface> up|down" },
5908 { "process-exists", control_process_exists, false, true,
5909 "check if a process exists on a node", "<pid> [<srvid>]" },
5910 { "getdbmap", control_getdbmap, false, true,
5911 "show attached databases", NULL },
5912 { "getdbstatus", control_getdbstatus, false, true,
5913 "show database status", "<dbname|dbid>" },
5914 { "catdb", control_catdb, false, false,
5915 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5916 { "cattdb", control_cattdb, false, false,
5917 "dump local ctdb database", "<dbname|dbid>" },
5918 { "getcapabilities", control_getcapabilities, false, true,
5919 "show node capabilities", NULL },
5920 { "pnn", control_pnn, false, false,
5921 "show the pnn of the currnet node", NULL },
5922 { "lvs", control_lvs, false, false,
5923 "show lvs configuration", "leader|list|status" },
5924 { "setdebug", control_setdebug, false, true,
5925 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5926 { "getdebug", control_getdebug, false, true,
5927 "get debug level", NULL },
5928 { "attach", control_attach, false, false,
5929 "attach a database", "<dbname> [persistent|replicated]" },
5930 { "detach", control_detach, false, false,
5931 "detach database(s)", "<dbname|dbid> ..." },
5932 { "dumpmemory", control_dumpmemory, false, true,
5933 "dump ctdbd memory map", NULL },
5934 { "rddumpmemory", control_rddumpmemory, false, true,
5935 "dump recoverd memory map", NULL },
5936 { "getpid", control_getpid, false, true,
5937 "get ctdbd process ID", NULL },
5938 { "disable", control_disable, false, true,
5939 "disable a node", NULL },
5940 { "enable", control_enable, false, true,
5941 "enable a node", NULL },
5942 { "stop", control_stop, false, true,
5943 "stop a node", NULL },
5944 { "continue", control_continue, false, true,
5945 "continue a stopped node", NULL },
5946 { "ban", control_ban, false, true,
5947 "ban a node", "<bantime>"},
5948 { "unban", control_unban, false, true,
5949 "unban a node", NULL },
5950 { "shutdown", control_shutdown, false, true,
5951 "shutdown ctdb daemon", NULL },
5952 { "recover", control_recover, false, true,
5953 "force recovery", NULL },
5954 { "sync", control_ipreallocate, false, true,
5955 "run ip reallocation (deprecated)", NULL },
5956 { "ipreallocate", control_ipreallocate, false, true,
5957 "run ip reallocation", NULL },
5958 { "gratarp", control_gratarp, false, true,
5959 "send a gratuitous arp", "<ip> <interface>" },
5960 { "tickle", control_tickle, true, false,
5961 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5962 { "gettickles", control_gettickles, false, true,
5963 "get the list of tickles", "<ip> [<port>]" },
5964 { "addtickle", control_addtickle, false, true,
5965 "add a tickle", "<ip>:<port> <ip>:<port>" },
5966 { "deltickle", control_deltickle, false, true,
5967 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5968 { "listnodes", control_listnodes, true, true,
5969 "list nodes in the cluster", NULL },
5970 { "reloadnodes", control_reloadnodes, false, false,
5971 "reload the nodes file all nodes", NULL },
5972 { "moveip", control_moveip, false, false,
5973 "move an ip address to another node", "<ip> <node>" },
5974 { "addip", control_addip, false, true,
5975 "add an ip address to a node", "<ip/mask> <iface>" },
5976 { "delip", control_delip, false, true,
5977 "delete an ip address from a node", "<ip>" },
5978 { "backupdb", control_backupdb, false, false,
5979 "backup a database into a file", "<dbname|dbid> <file>" },
5980 { "restoredb", control_restoredb, false, false,
5981 "restore a database from a file", "<file> [dbname]" },
5982 { "dumpdbbackup", control_dumpdbbackup, true, false,
5983 "dump database from a backup file", "<file>" },
5984 { "wipedb", control_wipedb, false, false,
5985 "wipe the contents of a database.", "<dbname|dbid>"},
5986 { "recmaster", control_recmaster, false, true,
5987 "show the pnn for the recovery master", NULL },
5988 { "event", control_event, true, false,
5989 "event and event script commands", NULL },
5990 { "scriptstatus", control_scriptstatus, true, false,
5991 "show event script status",
5992 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5993 { "natgw", control_natgw, false, false,
5994 "show natgw configuration", "leader|list|status" },
5995 { "getreclock", control_getreclock, false, true,
5996 "get recovery lock file", NULL },
5997 { "setlmasterrole", control_setlmasterrole, false, true,
5998 "set LMASTER role", "on|off" },
5999 { "setrecmasterrole", control_setrecmasterrole, false, true,
6000 "set RECMASTER role", "on|off"},
6001 { "setdbreadonly", control_setdbreadonly, false, true,
6002 "enable readonly records", "<dbname|dbid>" },
6003 { "setdbsticky", control_setdbsticky, false, true,
6004 "enable sticky records", "<dbname|dbid>"},
6005 { "pfetch", control_pfetch, false, false,
6006 "fetch record from persistent database", "<dbname|dbid> <key>" },
6007 { "pstore", control_pstore, false, false,
6008 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6009 { "pdelete", control_pdelete, false, false,
6010 "delete record from persistent database", "<dbname|dbid> <key>" },
6011 { "ptrans", control_ptrans, false, false,
6012 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6013 { "tfetch", control_tfetch, false, true,
6014 "fetch a record", "<tdb-file> <key> [<file>]" },
6015 { "tstore", control_tstore, false, true,
6016 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6017 { "readkey", control_readkey, false, false,
6018 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6019 { "writekey", control_writekey, false, false,
6020 "write value for a database key", "<dbname|dbid> <key> <value>" },
6021 { "deletekey", control_deletekey, false, false,
6022 "delete a database key", "<dbname|dbid> <key>" },
6023 { "checktcpport", control_checktcpport, true, false,
6024 "check if a service is bound to a specific tcp port or not", "<port>" },
6025 { "getdbseqnum", control_getdbseqnum, false, false,
6026 "get database sequence number", "<dbname|dbid>" },
6027 { "nodestatus", control_nodestatus, false, true,
6028 "show and return node status", "[all|<pnn-list>]" },
6029 { "dbstatistics", control_dbstatistics, false, true,
6030 "show database statistics", "<dbname|dbid>" },
6031 { "reloadips", control_reloadips, false, false,
6032 "reload the public addresses file", "[all|<pnn-list>]" },
6035 static const struct ctdb_cmd *match_command(const char *command)
6037 const struct ctdb_cmd *cmd;
6038 size_t i;
6040 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6041 cmd = &ctdb_commands[i];
6042 if (strlen(command) == strlen(cmd->name) &&
6043 strncmp(command, cmd->name, strlen(command)) == 0) {
6044 return cmd;
6048 return NULL;
6053 * Show usage message
6055 static void usage_full(void)
6057 size_t i;
6059 poptPrintHelp(pc, stdout, 0);
6060 printf("\nCommands:\n");
6061 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6062 printf(" %-15s %-27s %s\n",
6063 ctdb_commands[i].name,
6064 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6065 ctdb_commands[i].msg);
6069 static void usage(const char *command)
6071 const struct ctdb_cmd *cmd;
6073 if (command == NULL) {
6074 usage_full();
6075 exit(1);
6078 cmd = match_command(command);
6079 if (cmd == NULL) {
6080 usage_full();
6081 } else {
6082 poptPrintUsage(pc, stdout, 0);
6083 printf("\nCommands:\n");
6084 printf(" %-15s %-27s %s\n",
6085 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6088 exit(1);
6091 struct poptOption cmdline_options[] = {
6092 POPT_AUTOHELP
6094 .longName = "debug",
6095 .shortName = 'd',
6096 .argInfo = POPT_ARG_STRING,
6097 .arg = &options.debuglevelstr,
6098 .val = 0,
6099 .descrip = "debug level",
6102 .longName = "timelimit",
6103 .shortName = 't',
6104 .argInfo = POPT_ARG_INT,
6105 .arg = &options.timelimit,
6106 .val = 0,
6107 .descrip = "timelimit (in seconds)",
6110 .longName = "node",
6111 .shortName = 'n',
6112 .argInfo = POPT_ARG_INT,
6113 .arg = &options.pnn,
6114 .val = 0,
6115 .descrip = "node specification - integer",
6118 .longName = NULL,
6119 .shortName = 'Y',
6120 .argInfo = POPT_ARG_NONE,
6121 .arg = &options.machinereadable,
6122 .val = 0,
6123 .descrip = "enable machine readable output",
6126 .longName = "separator",
6127 .shortName = 'x',
6128 .argInfo = POPT_ARG_STRING,
6129 .arg = &options.sep,
6130 .val = 0,
6131 .descrip = "specify separator for machine readable output",
6132 .argDescrip = "CHAR",
6135 .shortName = 'X',
6136 .argInfo = POPT_ARG_NONE,
6137 .arg = &options.machineparsable,
6138 .val = 0,
6139 .descrip = "enable machine parsable output with separator |",
6142 .longName = "verbose",
6143 .shortName = 'v',
6144 .argInfo = POPT_ARG_NONE,
6145 .arg = &options.verbose,
6146 .val = 0,
6147 .descrip = "enable verbose output",
6150 .longName = "maxruntime",
6151 .shortName = 'T',
6152 .argInfo = POPT_ARG_INT,
6153 .arg = &options.maxruntime,
6154 .val = 0,
6155 .descrip = "die if runtime exceeds this limit (in seconds)",
6157 POPT_TABLEEND
6160 static int process_command(const struct ctdb_cmd *cmd, int argc,
6161 const char **argv)
6163 TALLOC_CTX *tmp_ctx;
6164 struct ctdb_context *ctdb;
6165 const char *ctdb_socket;
6166 int ret;
6167 bool status;
6168 uint64_t srvid_offset;
6170 tmp_ctx = talloc_new(NULL);
6171 if (tmp_ctx == NULL) {
6172 fprintf(stderr, "Memory allocation error\n");
6173 goto fail;
6176 if (cmd->without_daemon) {
6177 if (options.pnn != -1) {
6178 fprintf(stderr,
6179 "Cannot specify node for command %s\n",
6180 cmd->name);
6181 goto fail;
6184 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6185 talloc_free(tmp_ctx);
6186 return ret;
6189 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6190 if (ctdb == NULL) {
6191 fprintf(stderr, "Memory allocation error\n");
6192 goto fail;
6195 ctdb->ev = tevent_context_init(ctdb);
6196 if (ctdb->ev == NULL) {
6197 fprintf(stderr, "Failed to initialize tevent\n");
6198 goto fail;
6201 ctdb_socket = path_socket(ctdb, "ctdbd");
6202 if (ctdb_socket == NULL) {
6203 fprintf(stderr, "Memory allocation error\n");
6204 goto fail;
6207 ret = ctdb_client_init(ctdb, ctdb->ev, ctdb_socket, &ctdb->client);
6208 if (ret != 0) {
6209 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6210 ctdb_socket);
6212 if (!find_node_xpnn(ctdb, NULL)) {
6213 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6215 goto fail;
6218 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6219 srvid_offset = getpid() & 0xFFFF;
6220 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6222 if (options.pnn != -1) {
6223 status = verify_pnn(ctdb, options.pnn);
6224 if (! status) {
6225 goto fail;
6228 ctdb->cmd_pnn = options.pnn;
6229 } else {
6230 ctdb->cmd_pnn = ctdb->pnn;
6233 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6234 fprintf(stderr, "Node cannot be specified for command %s\n",
6235 cmd->name);
6236 goto fail;
6239 ctdb->leader_pnn = CTDB_UNKNOWN_PNN;
6240 ret = ctdb_client_set_message_handler(ctdb->ev,
6241 ctdb->client,
6242 CTDB_SRVID_LEADER,
6243 leader_handler,
6244 ctdb);
6245 if (ret != 0) {
6246 fprintf(stderr, "Failed to setup leader handler\n");
6247 goto fail;
6250 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6251 talloc_free(tmp_ctx);
6252 return ret;
6254 fail:
6255 talloc_free(tmp_ctx);
6256 return 1;
6259 static void signal_handler(int sig)
6261 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6264 static void alarm_handler(int sig)
6266 /* Kill any child processes */
6267 signal(SIGTERM, signal_handler);
6268 kill(0, SIGTERM);
6270 _exit(1);
6273 int main(int argc, const char *argv[])
6275 int opt;
6276 const char **extra_argv;
6277 int extra_argc;
6278 const struct ctdb_cmd *cmd;
6279 const char *test_mode;
6280 int loglevel;
6281 bool ok;
6282 int ret = 0;
6284 setlinebuf(stdout);
6286 /* Set default options */
6287 options.debuglevelstr = NULL;
6288 options.timelimit = 10;
6289 options.sep = "|";
6290 options.maxruntime = 0;
6291 options.pnn = -1;
6293 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6294 POPT_CONTEXT_KEEP_FIRST);
6295 while ((opt = poptGetNextOpt(pc)) != -1) {
6296 fprintf(stderr, "Invalid option %s: %s\n",
6297 poptBadOption(pc, 0), poptStrerror(opt));
6298 exit(1);
6301 if (options.maxruntime == 0) {
6302 const char *ctdb_timeout;
6304 ctdb_timeout = getenv("CTDB_TIMEOUT");
6305 if (ctdb_timeout != NULL) {
6306 options.maxruntime = smb_strtoul(ctdb_timeout,
6307 NULL,
6309 &ret,
6310 SMB_STR_STANDARD);
6311 if (ret != 0) {
6312 fprintf(stderr, "Invalid value CTDB_TIMEOUT\n");
6313 exit(1);
6315 } else {
6316 options.maxruntime = 120;
6320 if (options.machineparsable) {
6321 options.machinereadable = 1;
6324 /* setup the remaining options for the commands */
6325 extra_argc = 0;
6326 extra_argv = poptGetArgs(pc);
6327 if (extra_argv) {
6328 extra_argv++;
6329 while (extra_argv[extra_argc]) extra_argc++;
6332 if (extra_argc < 1) {
6333 usage(NULL);
6336 cmd = match_command(extra_argv[0]);
6337 if (cmd == NULL) {
6338 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6339 exit(1);
6342 /* Enable logging */
6343 setup_logging("ctdb", DEBUG_STDERR);
6344 ok = debug_level_parse(options.debuglevelstr, &loglevel);
6345 if (!ok) {
6346 loglevel = DEBUG_ERR;
6348 debuglevel_set(loglevel);
6350 /* Stop process group kill in alarm_handler() from killing tests */
6351 test_mode = getenv("CTDB_TEST_MODE");
6352 if (test_mode != NULL) {
6353 const char *have_setpgid = getenv("CTDB_TOOL_SETPGID");
6354 if (have_setpgid == NULL) {
6355 setpgid(0, 0);
6356 setenv("CTDB_TOOL_SETPGID", "1", 1);
6360 signal(SIGALRM, alarm_handler);
6361 alarm(options.maxruntime);
6363 ret = process_command(cmd, extra_argc, extra_argv);
6364 if (ret == -1) {
6365 ret = 1;
6368 (void)poptFreeContext(pc);
6370 return ret;