auth/spnego: make use of GENSEC_UPDATE_IS_NTERROR() in gensec_spnego_create_negTokenI...
[Samba.git] / ctdb / tools / ctdb.c
blob98f63e8b2a084fc6661d3337bb55c0d6ea1ca0b0
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 "ctdb_version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
38 #include "common/db_hash.h"
39 #include "common/logging.h"
40 #include "protocol/protocol.h"
41 #include "protocol/protocol_api.h"
42 #include "common/system.h"
43 #include "client/client.h"
44 #include "client/client_sync.h"
46 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
48 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
49 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
51 static struct {
52 const char *socket;
53 const char *debuglevelstr;
54 int timelimit;
55 int pnn;
56 int machinereadable;
57 const char *sep;
58 int machineparsable;
59 int verbose;
60 int maxruntime;
61 int printemptyrecords;
62 int printdatasize;
63 int printlmaster;
64 int printhash;
65 int printrecordflags;
66 } options;
68 static poptContext pc;
70 struct ctdb_context {
71 struct tevent_context *ev;
72 struct ctdb_client_context *client;
73 struct ctdb_node_map *nodemap;
74 uint32_t pnn, cmd_pnn;
75 uint64_t srvid;
78 static void usage(const char *command);
81 * Utility Functions
84 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
86 return (tv2->tv_sec - tv->tv_sec) +
87 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
90 static struct ctdb_node_and_flags *get_node_by_pnn(
91 struct ctdb_node_map *nodemap,
92 uint32_t pnn)
94 int i;
96 for (i=0; i<nodemap->num; i++) {
97 if (nodemap->node[i].pnn == pnn) {
98 return &nodemap->node[i];
101 return NULL;
104 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
106 static const struct {
107 uint32_t flag;
108 const char *name;
109 } flag_names[] = {
110 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
111 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
112 { NODE_FLAGS_BANNED, "BANNED" },
113 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
114 { NODE_FLAGS_DELETED, "DELETED" },
115 { NODE_FLAGS_STOPPED, "STOPPED" },
116 { NODE_FLAGS_INACTIVE, "INACTIVE" },
118 char *flags_str = NULL;
119 int i;
121 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
122 if (flags & flag_names[i].flag) {
123 if (flags_str == NULL) {
124 flags_str = talloc_asprintf(mem_ctx,
125 "%s", flag_names[i].name);
126 } else {
127 flags_str = talloc_asprintf_append(flags_str,
128 "|%s", flag_names[i].name);
130 if (flags_str == NULL) {
131 return "OUT-OF-MEMORY";
135 if (flags_str == NULL) {
136 return "OK";
139 return flags_str;
142 static uint64_t next_srvid(struct ctdb_context *ctdb)
144 ctdb->srvid += 1;
145 return ctdb->srvid;
149 * Get consistent nodemap information.
151 * If nodemap is already cached, use that. If not get it.
152 * If the current node is BANNED, then get nodemap from "better" node.
154 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
156 TALLOC_CTX *tmp_ctx;
157 struct ctdb_node_map *nodemap;
158 struct ctdb_node_and_flags *node;
159 uint32_t current_node;
160 int ret;
162 if (force) {
163 TALLOC_FREE(ctdb->nodemap);
166 if (ctdb->nodemap != NULL) {
167 return ctdb->nodemap;
170 tmp_ctx = talloc_new(ctdb);
171 if (tmp_ctx == NULL) {
172 return false;
175 current_node = ctdb->pnn;
176 again:
177 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
178 current_node, TIMEOUT(), &nodemap);
179 if (ret != 0) {
180 fprintf(stderr, "Failed to get nodemap from node %u\n",
181 current_node);
182 goto failed;
185 node = get_node_by_pnn(nodemap, current_node);
186 if (node->flags & NODE_FLAGS_BANNED) {
187 /* Pick next node */
188 do {
189 current_node = (current_node + 1) % nodemap->num;
190 node = get_node_by_pnn(nodemap, current_node);
191 if (! (node->flags &
192 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
193 break;
195 } while (current_node != ctdb->pnn);
197 if (current_node == ctdb->pnn) {
198 /* Tried all nodes in the cluster */
199 fprintf(stderr, "Warning: All nodes are banned.\n");
200 goto failed;
203 goto again;
206 ctdb->nodemap = talloc_steal(ctdb, nodemap);
207 return nodemap;
209 failed:
210 talloc_free(tmp_ctx);
211 return NULL;
214 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
216 struct ctdb_node_map *nodemap;
217 bool found;
218 int i;
220 if (pnn == -1) {
221 return false;
224 nodemap = get_nodemap(ctdb, false);
225 if (nodemap == NULL) {
226 return false;
229 found = false;
230 for (i=0; i<nodemap->num; i++) {
231 if (nodemap->node[i].pnn == pnn) {
232 found = true;
233 break;
236 if (! found) {
237 fprintf(stderr, "Node %u does not exist\n", pnn);
238 return false;
241 if (nodemap->node[i].flags &
242 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
243 fprintf(stderr, "Node %u has status %s\n", pnn,
244 pretty_print_flags(ctdb, nodemap->node[i].flags));
245 return false;
248 return true;
251 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
252 struct ctdb_node_map *nodemap)
254 struct ctdb_node_map *nodemap2;
256 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
257 if (nodemap2 == NULL) {
258 return NULL;
261 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
262 nodemap->num);
263 if (nodemap2->node == NULL) {
264 talloc_free(nodemap2);
265 return NULL;
268 return nodemap2;
272 * Get the number and the list of matching nodes
274 * nodestring := NULL | all | pnn,[pnn,...]
276 * If nodestring is NULL, use the current node.
278 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
279 const char *nodestring,
280 struct ctdb_node_map **out)
282 struct ctdb_node_map *nodemap, *nodemap2;
283 struct ctdb_node_and_flags *node;
284 int i;
286 nodemap = get_nodemap(ctdb, false);
287 if (nodemap == NULL) {
288 return false;
291 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
292 if (nodemap2 == NULL) {
293 return false;
296 if (nodestring == NULL) {
297 for (i=0; i<nodemap->num; i++) {
298 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
299 nodemap2->node[0] = nodemap->node[i];
300 break;
303 nodemap2->num = 1;
305 goto done;
308 if (strcmp(nodestring, "all") == 0) {
309 for (i=0; i<nodemap->num; i++) {
310 nodemap2->node[i] = nodemap->node[i];
312 nodemap2->num = nodemap->num;
314 goto done;
315 } else {
316 char *ns, *tok;
318 ns = talloc_strdup(mem_ctx, nodestring);
319 if (ns == NULL) {
320 return false;
323 tok = strtok(ns, ",");
324 while (tok != NULL) {
325 uint32_t pnn;
326 char *endptr;
328 pnn = (uint32_t)strtoul(tok, &endptr, 0);
329 if (pnn == 0 && tok == endptr) {
330 fprintf(stderr, "Invalid node %s\n", tok);
331 return false;
334 node = get_node_by_pnn(nodemap, pnn);
335 if (node == NULL) {
336 fprintf(stderr, "Node %u does not exist\n",
337 pnn);
338 return false;
341 nodemap2->node[nodemap2->num] = *node;
342 nodemap2->num += 1;
344 tok = strtok(NULL, ",");
348 done:
349 *out = nodemap2;
350 return true;
353 /* Compare IP address */
354 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
356 bool ret = false;
358 if (ip1->sa.sa_family != ip2->sa.sa_family) {
359 return false;
362 switch (ip1->sa.sa_family) {
363 case AF_INET:
364 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
365 sizeof(struct in_addr)) == 0);
366 break;
368 case AF_INET6:
369 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
370 sizeof(struct in6_addr)) == 0);
371 break;
374 return ret;
377 /* Append a node to a node map with given address and flags */
378 static bool node_map_add(struct ctdb_node_map *nodemap,
379 const char *nstr, uint32_t flags)
381 ctdb_sock_addr addr;
382 uint32_t num;
383 struct ctdb_node_and_flags *n;
385 if (! parse_ip(nstr, NULL, 0, &addr)) {
386 fprintf(stderr, "Invalid IP address %s\n", nstr);
387 return false;
390 num = nodemap->num;
391 nodemap->node = talloc_realloc(nodemap, nodemap->node,
392 struct ctdb_node_and_flags, num+1);
393 if (nodemap->node == NULL) {
394 return false;
397 n = &nodemap->node[num];
398 n->addr = addr;
399 n->pnn = num;
400 n->flags = flags;
402 nodemap->num = num+1;
403 return true;
406 /* Read a nodes file into a node map */
407 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
408 const char *nlist)
410 char **lines;
411 int nlines;
412 int i;
413 struct ctdb_node_map *nodemap;
415 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
416 if (nodemap == NULL) {
417 return NULL;
420 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
421 if (lines == NULL) {
422 return NULL;
425 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
426 nlines--;
429 for (i=0; i<nlines; i++) {
430 char *node;
431 uint32_t flags;
432 size_t len;
434 node = lines[i];
435 /* strip leading spaces */
436 while((*node == ' ') || (*node == '\t')) {
437 node++;
440 len = strlen(node);
442 /* strip trailing spaces */
443 while ((len > 1) &&
444 ((node[len-1] == ' ') || (node[len-1] == '\t')))
446 node[len-1] = '\0';
447 len--;
450 if (len == 0) {
451 continue;
453 if (*node == '#') {
454 /* A "deleted" node is a node that is
455 commented out in the nodes file. This is
456 used instead of removing a line, which
457 would cause subsequent nodes to change
458 their PNN. */
459 flags = NODE_FLAGS_DELETED;
460 node = discard_const("0.0.0.0");
461 } else {
462 flags = 0;
464 if (! node_map_add(nodemap, node, flags)) {
465 talloc_free(lines);
466 TALLOC_FREE(nodemap);
467 return NULL;
471 talloc_free(lines);
472 return nodemap;
475 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
477 struct ctdb_node_map *nodemap;
478 char *nodepath;
479 const char *nodes_list = NULL;
481 if (pnn != CTDB_UNKNOWN_PNN) {
482 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
483 if (nodepath != NULL) {
484 nodes_list = getenv(nodepath);
487 if (nodes_list == NULL) {
488 nodes_list = getenv("CTDB_NODES");
490 if (nodes_list == NULL) {
491 const char *basedir = getenv("CTDB_BASE");
492 if (basedir == NULL) {
493 basedir = CTDB_ETCDIR;
495 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
496 if (nodes_list == NULL) {
497 fprintf(stderr, "Memory allocation error\n");
498 return NULL;
502 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
503 if (nodemap == NULL) {
504 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
505 nodes_list);
506 return NULL;
509 return nodemap;
512 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
513 struct ctdb_context *ctdb,
514 struct ctdb_dbid_map *dbmap,
515 const char *db_name)
517 struct ctdb_dbid *db = NULL;
518 const char *name;
519 int ret, i;
521 for (i=0; i<dbmap->num; i++) {
522 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
523 ctdb->pnn, TIMEOUT(),
524 dbmap->dbs[i].db_id, &name);
525 if (ret != 0) {
526 return false;
529 if (strcmp(db_name, name) == 0) {
530 talloc_free(discard_const(name));
531 db = &dbmap->dbs[i];
532 break;
536 return db;
539 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
540 const char *db_arg, uint32_t *db_id,
541 const char **db_name, uint8_t *db_flags)
543 struct ctdb_dbid_map *dbmap;
544 struct ctdb_dbid *db = NULL;
545 uint32_t id = 0;
546 const char *name = NULL;
547 int ret, i;
549 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
550 ctdb->pnn, TIMEOUT(), &dbmap);
551 if (ret != 0) {
552 return false;
555 if (strncmp(db_arg, "0x", 2) == 0) {
556 id = strtoul(db_arg, NULL, 0);
557 for (i=0; i<dbmap->num; i++) {
558 if (id == dbmap->dbs[i].db_id) {
559 db = &dbmap->dbs[i];
560 break;
563 } else {
564 name = db_arg;
565 db = db_find(mem_ctx, ctdb, dbmap, name);
568 if (db == NULL) {
569 fprintf(stderr, "No database matching '%s' found\n", db_arg);
570 return false;
573 if (name == NULL) {
574 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
575 ctdb->pnn, TIMEOUT(), id, &name);
576 if (ret != 0) {
577 return false;
581 if (db_id != NULL) {
582 *db_id = db->db_id;
584 if (db_name != NULL) {
585 *db_name = talloc_strdup(mem_ctx, name);
587 if (db_flags != NULL) {
588 *db_flags = db->flags;
590 return true;
593 static int h2i(char h)
595 if (h >= 'a' && h <= 'f') {
596 return h - 'a' + 10;
598 if (h >= 'A' && h <= 'F') {
599 return h - 'f' + 10;
601 return h - '0';
604 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
605 TDB_DATA *out)
607 int i;
608 TDB_DATA data;
610 if (len & 0x01) {
611 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
612 str);
613 return EINVAL;
616 data.dsize = len / 2;
617 data.dptr = talloc_size(mem_ctx, data.dsize);
618 if (data.dptr == NULL) {
619 return ENOMEM;
622 for (i=0; i<data.dsize; i++) {
623 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
626 *out = data;
627 return 0;
630 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
631 TDB_DATA *out)
633 TDB_DATA data;
634 int ret = 0;
636 if (strncmp(str, "0x", 2) == 0) {
637 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
638 } else {
639 data.dptr = talloc_memdup(mem_ctx, str, len);
640 if (data.dptr == NULL) {
641 return ENOMEM;
643 data.dsize = len;
646 *out = data;
647 return ret;
650 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
651 const char *path, int argc, const char **argv)
653 pid_t pid;
654 int save_errno, status, ret;
655 const char **new_argv;
656 int i;
658 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
659 if (new_argv == NULL) {
660 return ENOMEM;
663 new_argv[0] = path;
664 for (i=0; i<argc; i++) {
665 new_argv[i+1] = argv[i];
667 new_argv[argc+1] = NULL;
669 pid = fork();
670 if (pid < 0) {
671 save_errno = errno;
672 talloc_free(new_argv);
673 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
674 command, path, strerror(save_errno));
675 return save_errno;
678 if (pid == 0) {
679 ret = execv(path, discard_const(new_argv));
680 if (ret == -1) {
681 _exit(64+errno);
683 /* Should not happen */
684 _exit(64+ENOEXEC);
687 talloc_free(new_argv);
689 ret = waitpid(pid, &status, 0);
690 if (ret == -1) {
691 save_errno = errno;
692 fprintf(stderr, "waitpid() failed for %s - %s\n",
693 command, strerror(save_errno));
694 return save_errno;
697 if (WIFEXITED(status)) {
698 int pstatus = WEXITSTATUS(status);
699 if (WIFSIGNALED(status)) {
700 fprintf(stderr, "%s terminated with signal %d\n",
701 command, WTERMSIG(status));
702 ret = EINTR;
703 } else if (pstatus >= 64 && pstatus < 255) {
704 fprintf(stderr, "%s failed with error %d\n",
705 command, pstatus-64);
706 ret = pstatus - 64;
707 } else {
708 ret = pstatus;
710 return ret;
711 } else if (WIFSIGNALED(status)) {
712 fprintf(stderr, "%s terminated with signal %d\n",
713 command, WTERMSIG(status));
714 return EINTR;
717 return 0;
721 * Command Functions
724 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
725 int argc, const char **argv)
727 printf("%s\n", CTDB_VERSION_STRING);
728 return 0;
731 static bool partially_online(TALLOC_CTX *mem_ctx,
732 struct ctdb_context *ctdb,
733 struct ctdb_node_and_flags *node)
735 struct ctdb_iface_list *iface_list;
736 int ret, i;
737 bool status = false;
739 if (node->flags != 0) {
740 return false;
743 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
744 node->pnn, TIMEOUT(), &iface_list);
745 if (ret != 0) {
746 return false;
749 status = false;
750 for (i=0; i < iface_list->num; i++) {
751 if (iface_list->iface[i].link_state == 0) {
752 status = true;
753 break;
757 return status;
760 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
761 struct ctdb_context *ctdb,
762 struct ctdb_node_map *nodemap,
763 uint32_t mypnn)
765 struct ctdb_node_and_flags *node;
766 int i;
768 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
769 options.sep,
770 "Node", options.sep,
771 "IP", options.sep,
772 "Disconnected", options.sep,
773 "Banned", options.sep,
774 "Disabled", options.sep,
775 "Unhealthy", options.sep,
776 "Stopped", options.sep,
777 "Inactive", options.sep,
778 "PartiallyOnline", options.sep,
779 "ThisNode", options.sep);
781 for (i=0; i<nodemap->num; i++) {
782 node = &nodemap->node[i];
783 if (node->flags & NODE_FLAGS_DELETED) {
784 continue;
787 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
788 options.sep,
789 node->pnn, options.sep,
790 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
791 options.sep,
792 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
793 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
794 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
795 options.sep,
796 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
797 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
798 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
799 partially_online(mem_ctx, ctdb, node), options.sep,
800 (node->pnn == mypnn)?'Y':'N', options.sep);
805 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
806 struct ctdb_node_map *nodemap, uint32_t mypnn,
807 bool print_header)
809 struct ctdb_node_and_flags *node;
810 int num_deleted_nodes = 0;
811 int i;
813 for (i=0; i<nodemap->num; i++) {
814 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
815 num_deleted_nodes++;
819 if (print_header) {
820 if (num_deleted_nodes == 0) {
821 printf("Number of nodes:%d\n", nodemap->num);
822 } else {
823 printf("Number of nodes:%d "
824 "(including %d deleted nodes)\n",
825 nodemap->num, num_deleted_nodes);
829 for (i=0; i<nodemap->num; i++) {
830 node = &nodemap->node[i];
831 if (node->flags & NODE_FLAGS_DELETED) {
832 continue;
835 printf("pnn:%u %-16s %s%s\n",
836 node->pnn,
837 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
838 partially_online(mem_ctx, ctdb, node) ?
839 "PARTIALLYONLINE" :
840 pretty_print_flags(mem_ctx, node->flags),
841 node->pnn == mypnn ? " (THIS NODE)" : "");
845 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
846 struct ctdb_node_map *nodemap, uint32_t mypnn,
847 struct ctdb_vnn_map *vnnmap, int recmode,
848 uint32_t recmaster)
850 int i;
852 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
854 if (vnnmap->generation == INVALID_GENERATION) {
855 printf("Generation:INVALID\n");
856 } else {
857 printf("Generation:%u\n", vnnmap->generation);
859 printf("Size:%d\n", vnnmap->size);
860 for (i=0; i<vnnmap->size; i++) {
861 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
864 printf("Recovery mode:%s (%d)\n",
865 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
866 recmode);
867 printf("Recovery master:%d\n", recmaster);
870 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
871 int argc, const char **argv)
873 struct ctdb_node_map *nodemap;
874 struct ctdb_vnn_map *vnnmap;
875 int recmode;
876 uint32_t recmaster;
877 int ret;
879 if (argc != 0) {
880 usage("status");
883 nodemap = get_nodemap(ctdb, false);
884 if (nodemap == NULL) {
885 return 1;
888 if (options.machinereadable == 1) {
889 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
890 return 0;
893 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
894 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
895 if (ret != 0) {
896 return ret;
899 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
900 ctdb->cmd_pnn, TIMEOUT(), &recmode);
901 if (ret != 0) {
902 return ret;
905 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
906 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
907 if (ret != 0) {
908 return ret;
911 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
912 recmode, recmaster);
913 return 0;
916 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
917 int argc, const char **argv)
919 struct ctdb_uptime *uptime;
920 int ret, tmp, days, hours, minutes, seconds;
922 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
923 ctdb->cmd_pnn, TIMEOUT(), &uptime);
924 if (ret != 0) {
925 return ret;
928 printf("Current time of node %-4u : %s",
929 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
931 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
932 seconds = tmp % 60; tmp /= 60;
933 minutes = tmp % 60; tmp /= 60;
934 hours = tmp % 24; tmp /= 24;
935 days = tmp;
937 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
938 days, hours, minutes, seconds,
939 ctime(&uptime->ctdbd_start_time.tv_sec));
941 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
942 seconds = tmp % 60; tmp /= 60;
943 minutes = tmp % 60; tmp /= 60;
944 hours = tmp % 24; tmp /= 24;
945 days = tmp;
947 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
948 days, hours, minutes, seconds,
949 ctime(&uptime->last_recovery_finished.tv_sec));
951 printf("Duration of last recovery/failover: %lf seconds\n",
952 timeval_delta(&uptime->last_recovery_finished,
953 &uptime->last_recovery_started));
955 return 0;
958 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
959 int argc, const char **argv)
961 struct timeval tv;
962 int ret, num_clients;
964 tv = timeval_current();
965 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
966 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
967 if (ret != 0) {
968 return ret;
971 printf("response from %u time=%.6f sec (%d clients)\n",
972 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
973 return 0;
976 const char *runstate_to_string(enum ctdb_runstate runstate);
977 enum ctdb_runstate runstate_from_string(const char *runstate_str);
979 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
980 int argc, const char **argv)
982 enum ctdb_runstate runstate;
983 bool found;
984 int ret, i;
986 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
987 ctdb->cmd_pnn, TIMEOUT(), &runstate);
988 if (ret != 0) {
989 return ret;
992 found = true;
993 for (i=0; i<argc; i++) {
994 enum ctdb_runstate t;
996 found = false;
997 t = ctdb_runstate_from_string(argv[i]);
998 if (t == CTDB_RUNSTATE_UNKNOWN) {
999 printf("Invalid run state (%s)\n", argv[i]);
1000 return 1;
1003 if (t == runstate) {
1004 found = true;
1005 break;
1009 if (! found) {
1010 printf("CTDB not in required run state (got %s)\n",
1011 ctdb_runstate_to_string(runstate));
1012 return 1;
1015 printf("%s\n", ctdb_runstate_to_string(runstate));
1016 return 0;
1019 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1020 int argc, const char **argv)
1022 struct ctdb_var_list *tun_var_list;
1023 uint32_t value;
1024 int ret, i;
1025 bool found;
1027 if (argc != 1) {
1028 usage("getvar");
1031 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1032 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1033 if (ret != 0) {
1034 fprintf(stderr,
1035 "Failed to get list of variables from node %u\n",
1036 ctdb->cmd_pnn);
1037 return ret;
1040 found = false;
1041 for (i=0; i<tun_var_list->count; i++) {
1042 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1043 found = true;
1044 break;
1048 if (! found) {
1049 printf("No such tunable %s\n", argv[0]);
1050 return 1;
1053 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1054 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1055 if (ret != 0) {
1056 return ret;
1059 printf("%-26s = %u\n", argv[0], value);
1060 return 0;
1063 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1064 int argc, const char **argv)
1066 struct ctdb_var_list *tun_var_list;
1067 struct ctdb_tunable tunable;
1068 int ret, i;
1069 bool found;
1071 if (argc != 2) {
1072 usage("setvar");
1075 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1076 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1077 if (ret != 0) {
1078 fprintf(stderr,
1079 "Failed to get list of variables from node %u\n",
1080 ctdb->cmd_pnn);
1081 return ret;
1084 found = false;
1085 for (i=0; i<tun_var_list->count; i++) {
1086 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1087 found = true;
1088 break;
1092 if (! found) {
1093 printf("No such tunable %s\n", argv[0]);
1094 return 1;
1097 tunable.name = argv[0];
1098 tunable.value = strtoul(argv[1], NULL, 0);
1100 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1101 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1102 if (ret != 0) {
1103 if (ret == 1) {
1104 fprintf(stderr,
1105 "Setting obsolete tunable variable '%s'\n",
1106 tunable.name);
1107 return 0;
1111 return ret;
1114 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1115 int argc, const char **argv)
1117 struct ctdb_var_list *tun_var_list;
1118 int ret, i;
1120 if (argc != 0) {
1121 usage("listvars");
1124 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1125 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1126 if (ret != 0) {
1127 return ret;
1130 for (i=0; i<tun_var_list->count; i++) {
1131 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1134 return 0;
1137 const struct {
1138 const char *name;
1139 uint32_t offset;
1140 } stats_fields[] = {
1141 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1142 STATISTICS_FIELD(num_clients),
1143 STATISTICS_FIELD(frozen),
1144 STATISTICS_FIELD(recovering),
1145 STATISTICS_FIELD(num_recoveries),
1146 STATISTICS_FIELD(client_packets_sent),
1147 STATISTICS_FIELD(client_packets_recv),
1148 STATISTICS_FIELD(node_packets_sent),
1149 STATISTICS_FIELD(node_packets_recv),
1150 STATISTICS_FIELD(keepalive_packets_sent),
1151 STATISTICS_FIELD(keepalive_packets_recv),
1152 STATISTICS_FIELD(node.req_call),
1153 STATISTICS_FIELD(node.reply_call),
1154 STATISTICS_FIELD(node.req_dmaster),
1155 STATISTICS_FIELD(node.reply_dmaster),
1156 STATISTICS_FIELD(node.reply_error),
1157 STATISTICS_FIELD(node.req_message),
1158 STATISTICS_FIELD(node.req_control),
1159 STATISTICS_FIELD(node.reply_control),
1160 STATISTICS_FIELD(client.req_call),
1161 STATISTICS_FIELD(client.req_message),
1162 STATISTICS_FIELD(client.req_control),
1163 STATISTICS_FIELD(timeouts.call),
1164 STATISTICS_FIELD(timeouts.control),
1165 STATISTICS_FIELD(timeouts.traverse),
1166 STATISTICS_FIELD(locks.num_calls),
1167 STATISTICS_FIELD(locks.num_current),
1168 STATISTICS_FIELD(locks.num_pending),
1169 STATISTICS_FIELD(locks.num_failed),
1170 STATISTICS_FIELD(total_calls),
1171 STATISTICS_FIELD(pending_calls),
1172 STATISTICS_FIELD(childwrite_calls),
1173 STATISTICS_FIELD(pending_childwrite_calls),
1174 STATISTICS_FIELD(memory_used),
1175 STATISTICS_FIELD(max_hop_count),
1176 STATISTICS_FIELD(total_ro_delegations),
1177 STATISTICS_FIELD(total_ro_revokes),
1180 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1182 static void print_statistics_machine(struct ctdb_statistics *s,
1183 bool show_header)
1185 int i;
1187 if (show_header) {
1188 printf("CTDB version%s", options.sep);
1189 printf("Current time of statistics%s", options.sep);
1190 printf("Statistics collected since%s", options.sep);
1191 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1192 printf("%s%s", stats_fields[i].name, options.sep);
1194 printf("num_reclock_ctdbd_latency%s", options.sep);
1195 printf("min_reclock_ctdbd_latency%s", options.sep);
1196 printf("avg_reclock_ctdbd_latency%s", options.sep);
1197 printf("max_reclock_ctdbd_latency%s", options.sep);
1199 printf("num_reclock_recd_latency%s", options.sep);
1200 printf("min_reclock_recd_latency%s", options.sep);
1201 printf("avg_reclock_recd_latency%s", options.sep);
1202 printf("max_reclock_recd_latency%s", options.sep);
1204 printf("num_call_latency%s", options.sep);
1205 printf("min_call_latency%s", options.sep);
1206 printf("avg_call_latency%s", options.sep);
1207 printf("max_call_latency%s", options.sep);
1209 printf("num_lockwait_latency%s", options.sep);
1210 printf("min_lockwait_latency%s", options.sep);
1211 printf("avg_lockwait_latency%s", options.sep);
1212 printf("max_lockwait_latency%s", options.sep);
1214 printf("num_childwrite_latency%s", options.sep);
1215 printf("min_childwrite_latency%s", options.sep);
1216 printf("avg_childwrite_latency%s", options.sep);
1217 printf("max_childwrite_latency%s", options.sep);
1218 printf("\n");
1221 printf("%u%s", CTDB_PROTOCOL, options.sep);
1222 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1223 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1224 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1225 printf("%u%s",
1226 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1227 options.sep);
1229 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1230 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1231 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1232 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1234 printf("%u%s", s->reclock.recd.num, options.sep);
1235 printf("%.6f%s", s->reclock.recd.min, options.sep);
1236 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1237 printf("%.6f%s", s->reclock.recd.max, options.sep);
1239 printf("%d%s", s->call_latency.num, options.sep);
1240 printf("%.6f%s", s->call_latency.min, options.sep);
1241 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1242 printf("%.6f%s", s->call_latency.max, options.sep);
1244 printf("%d%s", s->childwrite_latency.num, options.sep);
1245 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1246 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1247 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1248 printf("\n");
1251 static void print_statistics(struct ctdb_statistics *s)
1253 int tmp, days, hours, minutes, seconds;
1254 int i;
1255 const char *prefix = NULL;
1256 int preflen = 0;
1258 tmp = s->statistics_current_time.tv_sec -
1259 s->statistics_start_time.tv_sec;
1260 seconds = tmp % 60; tmp /= 60;
1261 minutes = tmp % 60; tmp /= 60;
1262 hours = tmp % 24; tmp /= 24;
1263 days = tmp;
1265 printf("CTDB version %u\n", CTDB_PROTOCOL);
1266 printf("Current time of statistics : %s",
1267 ctime(&s->statistics_current_time.tv_sec));
1268 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1269 days, hours, minutes, seconds,
1270 ctime(&s->statistics_start_time.tv_sec));
1272 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1273 if (strchr(stats_fields[i].name, '.') != NULL) {
1274 preflen = strcspn(stats_fields[i].name, ".") + 1;
1275 if (! prefix ||
1276 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1277 prefix = stats_fields[i].name;
1278 printf(" %*.*s\n", preflen-1, preflen-1,
1279 stats_fields[i].name);
1281 } else {
1282 preflen = 0;
1284 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1285 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1286 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1289 printf(" hop_count_buckets:");
1290 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1291 printf(" %d", s->hop_count_bucket[i]);
1293 printf("\n");
1294 printf(" lock_buckets:");
1295 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1296 printf(" %d", s->locks.buckets[i]);
1298 printf("\n");
1299 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1300 "locks_latency MIN/AVG/MAX",
1301 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1302 s->locks.latency.max, s->locks.latency.num);
1304 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1305 "reclock_ctdbd MIN/AVG/MAX",
1306 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1307 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1309 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1310 "reclock_recd MIN/AVG/MAX",
1311 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1312 s->reclock.recd.max, s->reclock.recd.num);
1314 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1315 "call_latency MIN/AVG/MAX",
1316 s->call_latency.min, LATENCY_AVG(s->call_latency),
1317 s->call_latency.max, s->call_latency.num);
1319 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1320 "childwrite_latency MIN/AVG/MAX",
1321 s->childwrite_latency.min,
1322 LATENCY_AVG(s->childwrite_latency),
1323 s->childwrite_latency.max, s->childwrite_latency.num);
1326 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1327 int argc, const char **argv)
1329 struct ctdb_statistics *stats;
1330 int ret;
1332 if (argc != 0) {
1333 usage("statistics");
1336 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1337 ctdb->cmd_pnn, TIMEOUT(), &stats);
1338 if (ret != 0) {
1339 return ret;
1342 if (options.machinereadable) {
1343 print_statistics_machine(stats, true);
1344 } else {
1345 print_statistics(stats);
1348 return 0;
1351 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1352 struct ctdb_context *ctdb,
1353 int argc, const char **argv)
1355 int ret;
1357 if (argc != 0) {
1358 usage("statisticsreset");
1361 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1362 ctdb->cmd_pnn, TIMEOUT());
1363 if (ret != 0) {
1364 return ret;
1367 return 0;
1370 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1371 int argc, const char **argv)
1373 struct ctdb_statistics_list *slist;
1374 int ret, count = 0, i;
1375 bool show_header = true;
1377 if (argc > 1) {
1378 usage("stats");
1381 if (argc == 1) {
1382 count = atoi(argv[0]);
1385 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1386 ctdb->cmd_pnn, TIMEOUT(), &slist);
1387 if (ret != 0) {
1388 return ret;
1391 for (i=0; i<slist->num; i++) {
1392 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1393 continue;
1395 if (options.machinereadable == 1) {
1396 print_statistics_machine(&slist->stats[i],
1397 show_header);
1398 show_header = false;
1399 } else {
1400 print_statistics(&slist->stats[i]);
1402 if (count > 0 && i == count) {
1403 break;
1407 return 0;
1410 static int ctdb_public_ip_cmp(const void *a, const void *b)
1412 const struct ctdb_public_ip *ip_a = a;
1413 const struct ctdb_public_ip *ip_b = b;
1415 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1418 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1419 struct ctdb_public_ip_list *ips,
1420 struct ctdb_public_ip_info **ipinfo,
1421 bool all_nodes)
1423 int i, j;
1424 char *conf, *avail, *active;
1426 if (options.machinereadable == 1) {
1427 printf("%s%s%s%s%s", options.sep,
1428 "Public IP", options.sep,
1429 "Node", options.sep);
1430 if (options.verbose == 1) {
1431 printf("%s%s%s%s%s%s\n",
1432 "ActiveInterfaces", options.sep,
1433 "AvailableInterfaces", options.sep,
1434 "ConfiguredInterfaces", options.sep);
1435 } else {
1436 printf("\n");
1438 } else {
1439 if (all_nodes) {
1440 printf("Public IPs on ALL nodes\n");
1441 } else {
1442 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1446 for (i = 0; i < ips->num; i++) {
1448 if (options.machinereadable == 1) {
1449 printf("%s%s%s%d%s", options.sep,
1450 ctdb_sock_addr_to_string(
1451 mem_ctx, &ips->ip[i].addr),
1452 options.sep,
1453 (int)ips->ip[i].pnn, options.sep);
1454 } else {
1455 printf("%s", ctdb_sock_addr_to_string(
1456 mem_ctx, &ips->ip[i].addr));
1459 if (options.verbose == 0) {
1460 if (options.machinereadable == 1) {
1461 printf("\n");
1462 } else {
1463 printf(" %d\n", (int)ips->ip[i].pnn);
1465 continue;
1468 conf = NULL;
1469 avail = NULL;
1470 active = NULL;
1472 if (ipinfo[i] == NULL) {
1473 goto skip_ipinfo;
1476 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1477 struct ctdb_iface *iface;
1479 iface = &ipinfo[i]->ifaces->iface[j];
1480 if (conf == NULL) {
1481 conf = talloc_strdup(mem_ctx, iface->name);
1482 } else {
1483 conf = talloc_asprintf_append(
1484 conf, ",%s", iface->name);
1487 if (ipinfo[i]->active_idx == j) {
1488 active = iface->name;
1491 if (iface->link_state == 0) {
1492 continue;
1495 if (avail == NULL) {
1496 avail = talloc_strdup(mem_ctx, iface->name);
1497 } else {
1498 avail = talloc_asprintf_append(
1499 avail, ",%s", iface->name);
1503 skip_ipinfo:
1505 if (options.machinereadable == 1) {
1506 printf("%s%s%s%s%s%s\n",
1507 active ? active : "", options.sep,
1508 avail ? avail : "", options.sep,
1509 conf ? conf : "", options.sep);
1510 } else {
1511 printf(" node[%d] active[%s] available[%s]"
1512 " configured[%s]\n",
1513 (int)ips->ip[i].pnn, active ? active : "",
1514 avail ? avail : "", conf ? conf : "");
1519 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1520 size_t datalen, void *private_data)
1522 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1523 private_data, struct ctdb_public_ip_list);
1524 struct ctdb_public_ip *ip;
1526 ip = (struct ctdb_public_ip *)databuf;
1527 ips->ip[ips->num] = *ip;
1528 ips->num += 1;
1530 return 0;
1533 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1534 struct ctdb_public_ip_list **out)
1536 struct ctdb_node_map *nodemap;
1537 struct ctdb_public_ip_list *ips;
1538 struct db_hash_context *ipdb;
1539 uint32_t *pnn_list;
1540 int ret, count, i, j;
1542 nodemap = get_nodemap(ctdb, false);
1543 if (nodemap == NULL) {
1544 return 1;
1547 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1548 if (ret != 0) {
1549 goto failed;
1552 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1553 &pnn_list);
1554 if (count <= 0) {
1555 goto failed;
1558 for (i=0; i<count; i++) {
1559 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1560 pnn_list[i], TIMEOUT(),
1561 false, &ips);
1562 if (ret != 0) {
1563 goto failed;
1566 for (j=0; j<ips->num; j++) {
1567 struct ctdb_public_ip ip;
1569 ip.pnn = ips->ip[j].pnn;
1570 ip.addr = ips->ip[j].addr;
1572 if (pnn_list[i] == ip.pnn) {
1573 /* Node claims IP is hosted on it, so
1574 * save that information
1576 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1577 sizeof(ip.addr),
1578 (uint8_t *)&ip, sizeof(ip));
1579 if (ret != 0) {
1580 goto failed;
1582 } else {
1583 /* Node thinks IP is hosted elsewhere,
1584 * so overwrite with CTDB_UNKNOWN_PNN
1585 * if there's no existing entry
1587 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1588 sizeof(ip.addr));
1589 if (ret == ENOENT) {
1590 ip.pnn = CTDB_UNKNOWN_PNN;
1591 ret = db_hash_add(ipdb,
1592 (uint8_t *)&ip.addr,
1593 sizeof(ip.addr),
1594 (uint8_t *)&ip,
1595 sizeof(ip));
1596 if (ret != 0) {
1597 goto failed;
1603 TALLOC_FREE(ips);
1606 talloc_free(pnn_list);
1608 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1609 if (ret != 0) {
1610 goto failed;
1613 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1614 if (ips == NULL) {
1615 goto failed;
1618 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1619 if (ips->ip == NULL) {
1620 goto failed;
1623 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1624 if (ret != 0) {
1625 goto failed;
1628 if (count != ips->num) {
1629 goto failed;
1632 talloc_free(ipdb);
1634 *out = ips;
1635 return 0;
1637 failed:
1638 talloc_free(ipdb);
1639 return 1;
1642 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1643 int argc, const char **argv)
1645 struct ctdb_public_ip_list *ips;
1646 struct ctdb_public_ip_info **ipinfo;
1647 int ret, i;
1648 bool do_all = false;
1650 if (argc > 1) {
1651 usage("ip");
1654 if (argc == 1) {
1655 if (strcmp(argv[0], "all") == 0) {
1656 do_all = true;
1657 } else {
1658 usage("ip");
1662 if (do_all) {
1663 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1664 } else {
1665 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1666 ctdb->cmd_pnn, TIMEOUT(),
1667 false, &ips);
1669 if (ret != 0) {
1670 return ret;
1673 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1674 ctdb_public_ip_cmp);
1676 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1677 if (ipinfo == NULL) {
1678 return 1;
1681 for (i=0; i<ips->num; i++) {
1682 uint32_t pnn;
1683 if (do_all) {
1684 pnn = ips->ip[i].pnn;
1685 } else {
1686 pnn = ctdb->cmd_pnn;
1688 if (pnn == CTDB_UNKNOWN_PNN) {
1689 ipinfo[i] = NULL;
1690 continue;
1692 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1693 ctdb->client, pnn,
1694 TIMEOUT(), &ips->ip[i].addr,
1695 &ipinfo[i]);
1696 if (ret != 0) {
1697 return ret;
1701 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1702 return 0;
1705 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1706 int argc, const char **argv)
1708 struct ctdb_public_ip_info *ipinfo;
1709 ctdb_sock_addr addr;
1710 int ret, i;
1712 if (argc != 1) {
1713 usage("ipinfo");
1716 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1717 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1718 return 1;
1721 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1722 ctdb->cmd_pnn, TIMEOUT(), &addr,
1723 &ipinfo);
1724 if (ret != 0) {
1725 if (ret == -1) {
1726 printf("Node %u does not know about IP %s\n",
1727 ctdb->cmd_pnn, argv[0]);
1729 return ret;
1732 printf("Public IP[%s] info on node %u\n",
1733 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1734 ctdb->cmd_pnn);
1736 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1737 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1738 ipinfo->ip.pnn, ipinfo->ifaces->num);
1740 for (i=0; i<ipinfo->ifaces->num; i++) {
1741 struct ctdb_iface *iface;
1743 iface = &ipinfo->ifaces->iface[i];
1744 iface->name[CTDB_IFACE_SIZE] = '\0';
1745 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1746 i+1, iface->name,
1747 iface->link_state == 0 ? "down" : "up",
1748 iface->references,
1749 (i == ipinfo->active_idx) ? " (active)" : "");
1752 return 0;
1755 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1756 int argc, const char **argv)
1758 struct ctdb_iface_list *ifaces;
1759 int ret, i;
1761 if (argc != 0) {
1762 usage("ifaces");
1765 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1766 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1767 if (ret != 0) {
1768 return ret;
1771 if (ifaces->num == 0) {
1772 printf("No interfaces configured on node %u\n",
1773 ctdb->cmd_pnn);
1774 return 0;
1777 if (options.machinereadable) {
1778 printf("%s%s%s%s%s%s%s\n", options.sep,
1779 "Name", options.sep,
1780 "LinkStatus", options.sep,
1781 "References", options.sep);
1782 } else {
1783 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1786 for (i=0; i<ifaces->num; i++) {
1787 if (options.machinereadable) {
1788 printf("%s%s%s%u%s%u%s\n", options.sep,
1789 ifaces->iface[i].name, options.sep,
1790 ifaces->iface[i].link_state, options.sep,
1791 ifaces->iface[i].references, options.sep);
1792 } else {
1793 printf("name:%s link:%s references:%u\n",
1794 ifaces->iface[i].name,
1795 ifaces->iface[i].link_state ? "up" : "down",
1796 ifaces->iface[i].references);
1800 return 0;
1803 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1804 int argc, const char **argv)
1806 struct ctdb_iface_list *ifaces;
1807 struct ctdb_iface *iface;
1808 int ret, i;
1810 if (argc != 2) {
1811 usage("setifacelink");
1814 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1815 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1816 return 1;
1819 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1820 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1821 if (ret != 0) {
1822 fprintf(stderr,
1823 "Failed to get interface information from node %u\n",
1824 ctdb->cmd_pnn);
1825 return ret;
1828 iface = NULL;
1829 for (i=0; i<ifaces->num; i++) {
1830 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1831 iface = &ifaces->iface[i];
1832 break;
1836 if (iface == NULL) {
1837 printf("Interface %s not configured on node %u\n",
1838 argv[0], ctdb->cmd_pnn);
1839 return 1;
1842 if (strcmp(argv[1], "up") == 0) {
1843 iface->link_state = 1;
1844 } else if (strcmp(argv[1], "down") == 0) {
1845 iface->link_state = 0;
1846 } else {
1847 usage("setifacelink");
1848 return 1;
1851 iface->references = 0;
1853 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1854 ctdb->cmd_pnn, TIMEOUT(), iface);
1855 if (ret != 0) {
1856 return ret;
1859 return 0;
1862 static int control_process_exists(TALLOC_CTX *mem_ctx,
1863 struct ctdb_context *ctdb,
1864 int argc, const char **argv)
1866 pid_t pid;
1867 int ret, status;
1869 if (argc != 1) {
1870 usage("process-exists");
1873 pid = atoi(argv[0]);
1874 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1875 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1876 if (ret != 0) {
1877 return ret;
1880 if (status == 0) {
1881 printf("PID %u exists\n", pid);
1882 } else {
1883 printf("PID %u does not exist\n", pid);
1885 return status;
1888 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1889 int argc, const char **argv)
1891 struct ctdb_dbid_map *dbmap;
1892 int ret, i;
1894 if (argc != 0) {
1895 usage("getdbmap");
1898 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1899 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1900 if (ret != 0) {
1901 return ret;
1904 if (options.machinereadable == 1) {
1905 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1906 options.sep,
1907 "ID", options.sep,
1908 "Name", options.sep,
1909 "Path", options.sep,
1910 "Persistent", options.sep,
1911 "Sticky", options.sep,
1912 "Unhealthy", options.sep,
1913 "Readonly", options.sep,
1914 "Replicated", options.sep);
1915 } else {
1916 printf("Number of databases:%d\n", dbmap->num);
1919 for (i=0; i<dbmap->num; i++) {
1920 const char *name;
1921 const char *path;
1922 const char *health;
1923 bool persistent;
1924 bool readonly;
1925 bool sticky;
1926 bool replicated;
1927 uint32_t db_id;
1929 db_id = dbmap->dbs[i].db_id;
1931 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1932 ctdb->cmd_pnn, TIMEOUT(), db_id,
1933 &name);
1934 if (ret != 0) {
1935 return ret;
1938 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1939 ctdb->cmd_pnn, TIMEOUT(), db_id,
1940 &path);
1941 if (ret != 0) {
1942 return ret;
1945 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1946 ctdb->cmd_pnn, TIMEOUT(), db_id,
1947 &health);
1948 if (ret != 0) {
1949 return ret;
1952 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1953 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1954 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1955 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
1957 if (options.machinereadable == 1) {
1958 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1959 options.sep,
1960 db_id, options.sep,
1961 name, options.sep,
1962 path, options.sep,
1963 !! (persistent), options.sep,
1964 !! (sticky), options.sep,
1965 !! (health), options.sep,
1966 !! (readonly), options.sep,
1967 !! (replicated), options.sep);
1968 } else {
1969 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1970 db_id, name, path,
1971 persistent ? " PERSISTENT" : "",
1972 sticky ? " STICKY" : "",
1973 readonly ? " READONLY" : "",
1974 replicated ? " REPLICATED" : "",
1975 health ? " UNHEALTHY" : "");
1978 talloc_free(discard_const(name));
1979 talloc_free(discard_const(path));
1980 talloc_free(discard_const(health));
1983 return 0;
1986 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1987 int argc, const char **argv)
1989 uint32_t db_id;
1990 const char *db_name, *db_path, *db_health;
1991 uint8_t db_flags;
1992 int ret;
1994 if (argc != 1) {
1995 usage("getdbstatus");
1998 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
1999 return 1;
2002 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2003 ctdb->cmd_pnn, TIMEOUT(), db_id,
2004 &db_path);
2005 if (ret != 0) {
2006 return ret;
2009 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2010 ctdb->cmd_pnn, TIMEOUT(), db_id,
2011 &db_health);
2012 if (ret != 0) {
2013 return ret;
2016 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2017 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2018 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2019 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2020 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2021 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2022 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2023 return 0;
2026 struct dump_record_state {
2027 uint32_t count;
2030 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2032 static void dump_tdb_data(const char *name, TDB_DATA val)
2034 int i;
2036 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2037 for (i=0; i<val.dsize; i++) {
2038 if (ISASCII(val.dptr[i])) {
2039 fprintf(stdout, "%c", val.dptr[i]);
2040 } else {
2041 fprintf(stdout, "\\%02X", val.dptr[i]);
2044 fprintf(stdout, "\"\n");
2047 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2049 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2050 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2051 fprintf(stdout, "flags: 0x%08x", header->flags);
2052 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2053 fprintf(stdout, " MIGRATED_WITH_DATA");
2055 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2056 fprintf(stdout, " VACUUM_MIGRATED");
2058 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2059 fprintf(stdout, " AUTOMATIC");
2061 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2062 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2064 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2065 fprintf(stdout, " RO_HAVE_READONLY");
2067 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2068 fprintf(stdout, " RO_REVOKING_READONLY");
2070 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2071 fprintf(stdout, " RO_REVOKE_COMPLETE");
2073 fprintf(stdout, "\n");
2077 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2078 TDB_DATA key, TDB_DATA data, void *private_data)
2080 struct dump_record_state *state =
2081 (struct dump_record_state *)private_data;
2083 state->count += 1;
2085 dump_tdb_data("key", key);
2086 dump_ltdb_header(header);
2087 dump_tdb_data("data", data);
2088 fprintf(stdout, "\n");
2090 return 0;
2093 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2094 int argc, const char **argv)
2096 struct ctdb_db_context *db;
2097 const char *db_name;
2098 uint32_t db_id;
2099 uint8_t db_flags;
2100 struct dump_record_state state;
2101 int ret;
2103 if (argc != 1) {
2104 usage("catdb");
2107 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2108 return 1;
2111 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2112 db_flags, &db);
2113 if (ret != 0) {
2114 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2115 return ret;
2118 state.count = 0;
2120 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2121 ctdb->cmd_pnn, TIMEOUT(),
2122 dump_record, &state);
2124 printf("Dumped %u records\n", state.count);
2126 return ret;
2129 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2130 int argc, const char **argv)
2132 struct ctdb_db_context *db;
2133 const char *db_name;
2134 uint32_t db_id;
2135 uint8_t db_flags;
2136 struct dump_record_state state;
2137 int ret;
2139 if (argc != 1) {
2140 usage("catdb");
2143 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2144 return 1;
2147 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2148 db_flags, &db);
2149 if (ret != 0) {
2150 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2151 return ret;
2154 state.count = 0;
2155 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2157 printf("Dumped %u record(s)\n", state.count);
2159 return ret;
2162 static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2163 int argc, const char **argv)
2165 int mode, ret;
2167 if (argc != 0) {
2168 usage("getmonmode");
2171 ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
2172 ctdb->cmd_pnn, TIMEOUT(), &mode);
2173 if (ret != 0) {
2174 return ret;
2177 printf("%s\n",
2178 (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
2179 return 0;
2182 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2183 struct ctdb_context *ctdb,
2184 int argc, const char **argv)
2186 uint32_t caps;
2187 int ret;
2189 if (argc != 0) {
2190 usage("getcapabilities");
2193 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2194 ctdb->cmd_pnn, TIMEOUT(), &caps);
2195 if (ret != 0) {
2196 return ret;
2199 if (options.machinereadable == 1) {
2200 printf("%s%s%s%s%s\n",
2201 options.sep,
2202 "RECMASTER", options.sep,
2203 "LMASTER", options.sep);
2204 printf("%s%d%s%d%s\n", options.sep,
2205 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2206 !! (caps & CTDB_CAP_LMASTER), options.sep);
2207 } else {
2208 printf("RECMASTER: %s\n",
2209 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2210 printf("LMASTER: %s\n",
2211 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2214 return 0;
2217 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2218 int argc, const char **argv)
2220 printf("%u\n", ctdb_client_pnn(ctdb->client));
2221 return 0;
2224 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2225 int argc, const char **argv)
2227 char *t, *lvs_helper = NULL;
2229 if (argc != 1) {
2230 usage("lvs");
2233 t = getenv("CTDB_LVS_HELPER");
2234 if (t != NULL) {
2235 lvs_helper = talloc_strdup(mem_ctx, t);
2236 } else {
2237 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2238 CTDB_HELPER_BINDIR);
2241 if (lvs_helper == NULL) {
2242 fprintf(stderr, "Unable to set LVS helper\n");
2243 return 1;
2246 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2249 static int control_disable_monitor(TALLOC_CTX *mem_ctx,
2250 struct ctdb_context *ctdb,
2251 int argc, const char **argv)
2253 int ret;
2255 if (argc != 0) {
2256 usage("disablemonitor");
2259 ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2260 ctdb->cmd_pnn, TIMEOUT());
2261 if (ret != 0) {
2262 return ret;
2265 return 0;
2268 static int control_enable_monitor(TALLOC_CTX *mem_ctx,
2269 struct ctdb_context *ctdb,
2270 int argc, const char **argv)
2272 int ret;
2274 if (argc != 0) {
2275 usage("enablemonitor");
2278 ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2279 ctdb->cmd_pnn, TIMEOUT());
2280 if (ret != 0) {
2281 return ret;
2284 return 0;
2287 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2288 int argc, const char **argv)
2290 int log_level;
2291 int ret;
2292 bool found;
2294 if (argc != 1) {
2295 usage("setdebug");
2298 found = debug_level_parse(argv[0], &log_level);
2299 if (! found) {
2300 fprintf(stderr,
2301 "Invalid debug level '%s'. Valid levels are:\n",
2302 argv[0]);
2303 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2304 return 1;
2307 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2308 ctdb->cmd_pnn, TIMEOUT(), log_level);
2309 if (ret != 0) {
2310 return ret;
2313 return 0;
2316 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2317 int argc, const char **argv)
2319 int loglevel;
2320 const char *log_str;
2321 int ret;
2323 if (argc != 0) {
2324 usage("getdebug");
2327 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2328 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2329 if (ret != 0) {
2330 return ret;
2333 log_str = debug_level_to_string(loglevel);
2334 printf("%s\n", log_str);
2336 return 0;
2339 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2340 int argc, const char **argv)
2342 const char *db_name;
2343 uint8_t db_flags = 0;
2344 int ret;
2346 if (argc < 1 || argc > 2) {
2347 usage("attach");
2350 db_name = argv[0];
2351 if (argc == 2) {
2352 if (strcmp(argv[1], "persistent") == 0) {
2353 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2354 } else if (strcmp(argv[1], "readonly") == 0) {
2355 db_flags = CTDB_DB_FLAGS_READONLY;
2356 } else if (strcmp(argv[1], "sticky") == 0) {
2357 db_flags = CTDB_DB_FLAGS_STICKY;
2358 } else if (strcmp(argv[1], "replicated") == 0) {
2359 db_flags = CTDB_DB_FLAGS_REPLICATED;
2360 } else {
2361 usage("attach");
2365 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2366 db_flags, NULL);
2367 if (ret != 0) {
2368 return ret;
2371 return 0;
2374 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2375 int argc, const char **argv)
2377 const char *db_name;
2378 uint32_t db_id;
2379 uint8_t db_flags;
2380 struct ctdb_node_map *nodemap;
2381 int recmode;
2382 int ret, ret2, i;
2384 if (argc < 1) {
2385 usage("detach");
2388 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2389 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2390 if (ret != 0) {
2391 return ret;
2394 if (recmode == CTDB_RECOVERY_ACTIVE) {
2395 fprintf(stderr, "Database cannot be detached"
2396 " when recovery is active\n");
2397 return 1;
2400 nodemap = get_nodemap(ctdb, false);
2401 if (nodemap == NULL) {
2402 return 1;
2405 for (i=0; i<nodemap->num; i++) {
2406 uint32_t value;
2408 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2409 continue;
2411 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2412 continue;
2414 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2415 fprintf(stderr, "Database cannot be detached on"
2416 " inactive (stopped or banned) node %u\n",
2417 nodemap->node[i].pnn);
2418 return 1;
2421 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2422 nodemap->node[i].pnn, TIMEOUT(),
2423 "AllowClientDBAttach", &value);
2424 if (ret != 0) {
2425 fprintf(stderr,
2426 "Unable to get tunable AllowClientDBAttach"
2427 " from node %u\n", nodemap->node[i].pnn);
2428 return ret;
2431 if (value == 1) {
2432 fprintf(stderr,
2433 "Database access is still active on node %u."
2434 " Set AllowclientDBAttach=0 on all nodes.\n",
2435 nodemap->node[i].pnn);
2436 return 1;
2440 ret2 = 0;
2441 for (i=0; i<argc; i++) {
2442 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2443 &db_flags)) {
2444 continue;
2447 if (db_flags &
2448 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2449 fprintf(stderr,
2450 "Only volatile databases can be detached\n");
2451 return 1;
2454 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2455 if (ret != 0) {
2456 fprintf(stderr, "Database %s detach failed\n", db_name);
2457 ret2 = ret;
2461 return ret2;
2464 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2465 int argc, const char **argv)
2467 const char *mem_str;
2468 ssize_t n;
2469 int ret;
2471 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2472 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2473 if (ret != 0) {
2474 return ret;
2477 n = write(1, mem_str, strlen(mem_str)+1);
2478 if (n < 0 || n != strlen(mem_str)+1) {
2479 fprintf(stderr, "Failed to write talloc summary\n");
2480 return 1;
2483 return 0;
2486 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2488 bool *done = (bool *)private_data;
2489 ssize_t n;
2491 n = write(1, data.dptr, data.dsize);
2492 if (n < 0 || n != data.dsize) {
2493 fprintf(stderr, "Failed to write talloc summary\n");
2496 *done = true;
2499 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2500 int argc, const char **argv)
2502 struct ctdb_srvid_message msg = { 0 };
2503 int ret;
2504 bool done = false;
2506 msg.pnn = ctdb->pnn;
2507 msg.srvid = next_srvid(ctdb);
2509 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2510 msg.srvid, dump_memory, &done);
2511 if (ret != 0) {
2512 return ret;
2515 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2516 ctdb->cmd_pnn, &msg);
2517 if (ret != 0) {
2518 return ret;
2521 ctdb_client_wait(ctdb->ev, &done);
2522 return 0;
2525 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2526 int argc, const char **argv)
2528 pid_t pid;
2529 int ret;
2531 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2532 ctdb->cmd_pnn, TIMEOUT(), &pid);
2533 if (ret != 0) {
2534 return ret;
2537 printf("%u\n", pid);
2538 return 0;
2541 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2542 const char *desc, uint32_t flag, bool set_flag)
2544 struct ctdb_node_map *nodemap;
2545 bool flag_is_set;
2547 nodemap = get_nodemap(ctdb, false);
2548 if (nodemap == NULL) {
2549 return 1;
2552 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2553 if (set_flag == flag_is_set) {
2554 if (set_flag) {
2555 fprintf(stderr, "Node %u is already %s\n",
2556 ctdb->cmd_pnn, desc);
2557 } else {
2558 fprintf(stderr, "Node %u is not %s\n",
2559 ctdb->cmd_pnn, desc);
2561 return 0;
2564 return 1;
2567 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2568 uint32_t flag, bool set_flag)
2570 struct ctdb_node_map *nodemap;
2571 bool flag_is_set;
2573 while (1) {
2574 nodemap = get_nodemap(ctdb, true);
2575 if (nodemap == NULL) {
2576 fprintf(stderr,
2577 "Failed to get nodemap, trying again\n");
2578 sleep(1);
2579 continue;
2582 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2583 if (flag_is_set == set_flag) {
2584 break;
2587 sleep(1);
2591 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2592 struct ctdb_client_context *client,
2593 uint32_t destnode, struct timeval timeout,
2594 uint32_t set, uint32_t clear)
2596 struct ctdb_node_map *nodemap;
2597 struct ctdb_node_flag_change flag_change;
2598 struct ctdb_req_control request;
2599 uint32_t *pnn_list;
2600 int ret, count;
2602 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2603 tevent_timeval_zero(), &nodemap);
2604 if (ret != 0) {
2605 return ret;
2608 flag_change.pnn = destnode;
2609 flag_change.old_flags = nodemap->node[destnode].flags;
2610 flag_change.new_flags = flag_change.old_flags | set;
2611 flag_change.new_flags &= ~clear;
2613 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2614 if (count == -1) {
2615 return ENOMEM;
2618 ctdb_req_control_modify_flags(&request, &flag_change);
2619 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2620 tevent_timeval_zero(), &request,
2621 NULL, NULL);
2622 return ret;
2625 struct ipreallocate_state {
2626 int status;
2627 bool done;
2630 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2631 void *private_data)
2633 struct ipreallocate_state *state =
2634 (struct ipreallocate_state *)private_data;
2636 if (data.dsize != sizeof(int)) {
2637 /* Ignore packet */
2638 return;
2641 state->status = *(int *)data.dptr;
2642 state->done = true;
2645 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2647 struct ctdb_srvid_message msg = { 0 };
2648 struct ipreallocate_state state;
2649 int ret;
2651 msg.pnn = ctdb->pnn;
2652 msg.srvid = next_srvid(ctdb);
2654 state.done = false;
2655 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2656 msg.srvid,
2657 ipreallocate_handler, &state);
2658 if (ret != 0) {
2659 return ret;
2662 while (true) {
2663 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2664 ctdb->client,
2665 CTDB_BROADCAST_CONNECTED,
2666 &msg);
2667 if (ret != 0) {
2668 goto fail;
2671 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2672 TIMEOUT());
2673 if (ret != 0) {
2674 continue;
2677 if (state.status >= 0) {
2678 ret = 0;
2679 } else {
2680 ret = state.status;
2682 break;
2685 fail:
2686 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2687 msg.srvid, &state);
2688 return ret;
2691 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2692 int argc, const char **argv)
2694 int ret;
2696 if (argc != 0) {
2697 usage("disable");
2700 ret = check_flags(mem_ctx, ctdb, "disabled",
2701 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2702 if (ret == 0) {
2703 return 0;
2706 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2707 ctdb->cmd_pnn, TIMEOUT(),
2708 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2709 if (ret != 0) {
2710 fprintf(stderr,
2711 "Failed to set DISABLED flag on node %u\n",
2712 ctdb->cmd_pnn);
2713 return ret;
2716 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2717 return ipreallocate(mem_ctx, ctdb);
2720 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2721 int argc, const char **argv)
2723 int ret;
2725 if (argc != 0) {
2726 usage("enable");
2729 ret = check_flags(mem_ctx, ctdb, "disabled",
2730 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2731 if (ret == 0) {
2732 return 0;
2735 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2736 ctdb->cmd_pnn, TIMEOUT(),
2737 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2738 if (ret != 0) {
2739 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2740 ctdb->cmd_pnn);
2741 return ret;
2744 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2745 return ipreallocate(mem_ctx, ctdb);
2748 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2749 int argc, const char **argv)
2751 int ret;
2753 if (argc != 0) {
2754 usage("stop");
2757 ret = check_flags(mem_ctx, ctdb, "stopped",
2758 NODE_FLAGS_STOPPED, true);
2759 if (ret == 0) {
2760 return 0;
2763 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2764 ctdb->cmd_pnn, TIMEOUT());
2765 if (ret != 0) {
2766 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2767 return ret;
2770 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2771 return ipreallocate(mem_ctx, ctdb);
2774 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2775 int argc, const char **argv)
2777 int ret;
2779 if (argc != 0) {
2780 usage("continue");
2783 ret = check_flags(mem_ctx, ctdb, "stopped",
2784 NODE_FLAGS_STOPPED, false);
2785 if (ret == 0) {
2786 return 0;
2789 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2790 ctdb->cmd_pnn, TIMEOUT());
2791 if (ret != 0) {
2792 fprintf(stderr, "Failed to continue stopped node %u\n",
2793 ctdb->cmd_pnn);
2794 return ret;
2797 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2798 return ipreallocate(mem_ctx, ctdb);
2801 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2802 int argc, const char **argv)
2804 struct ctdb_ban_state ban_state;
2805 int ret;
2807 if (argc != 1) {
2808 usage("ban");
2811 ret = check_flags(mem_ctx, ctdb, "banned",
2812 NODE_FLAGS_BANNED, true);
2813 if (ret == 0) {
2814 return 0;
2817 ban_state.pnn = ctdb->cmd_pnn;
2818 ban_state.time = strtoul(argv[0], NULL, 0);
2820 if (ban_state.time == 0) {
2821 fprintf(stderr, "Ban time cannot be zero\n");
2822 return EINVAL;
2825 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2826 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2827 if (ret != 0) {
2828 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2829 return ret;
2832 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2833 return ipreallocate(mem_ctx, ctdb);
2837 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2838 int argc, const char **argv)
2840 struct ctdb_ban_state ban_state;
2841 int ret;
2843 if (argc != 0) {
2844 usage("unban");
2847 ret = check_flags(mem_ctx, ctdb, "banned",
2848 NODE_FLAGS_BANNED, false);
2849 if (ret == 0) {
2850 return 0;
2853 ban_state.pnn = ctdb->cmd_pnn;
2854 ban_state.time = 0;
2856 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2857 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2858 if (ret != 0) {
2859 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2860 return ret;
2863 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2864 return ipreallocate(mem_ctx, ctdb);
2868 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2869 int argc, const char **argv)
2871 int ret;
2873 if (argc != 0) {
2874 usage("shutdown");
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 return 0;
2887 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2888 uint32_t *generation)
2890 uint32_t recmaster;
2891 int recmode;
2892 struct ctdb_vnn_map *vnnmap;
2893 int ret;
2895 again:
2896 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2897 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2898 if (ret != 0) {
2899 fprintf(stderr, "Failed to find recovery master\n");
2900 return ret;
2903 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2904 recmaster, TIMEOUT(), &recmode);
2905 if (ret != 0) {
2906 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2907 recmaster);
2908 return ret;
2911 if (recmode == CTDB_RECOVERY_ACTIVE) {
2912 sleep(1);
2913 goto again;
2916 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2917 recmaster, TIMEOUT(), &vnnmap);
2918 if (ret != 0) {
2919 fprintf(stderr, "Failed to get generation from node %u\n",
2920 recmaster);
2921 return ret;
2924 if (vnnmap->generation == INVALID_GENERATION) {
2925 talloc_free(vnnmap);
2926 sleep(1);
2927 goto again;
2930 *generation = vnnmap->generation;
2931 talloc_free(vnnmap);
2932 return 0;
2936 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2937 int argc, const char **argv)
2939 uint32_t generation, next_generation;
2940 int ret;
2942 if (argc != 0) {
2943 usage("recover");
2946 ret = get_generation(mem_ctx, ctdb, &generation);
2947 if (ret != 0) {
2948 return ret;
2951 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2952 ctdb->cmd_pnn, TIMEOUT(),
2953 CTDB_RECOVERY_ACTIVE);
2954 if (ret != 0) {
2955 fprintf(stderr, "Failed to set recovery mode active\n");
2956 return ret;
2959 while (1) {
2960 ret = get_generation(mem_ctx, ctdb, &next_generation);
2961 if (ret != 0) {
2962 fprintf(stderr,
2963 "Failed to confirm end of recovery\n");
2964 return ret;
2967 if (next_generation != generation) {
2968 break;
2971 sleep (1);
2974 return 0;
2977 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2978 int argc, const char **argv)
2980 if (argc != 0) {
2981 usage("ipreallocate");
2984 return ipreallocate(mem_ctx, ctdb);
2987 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2988 struct ctdb_context *ctdb,
2989 int argc, const char **argv)
2991 uint32_t recmaster;
2992 int ret;
2994 if (argc != 0) {
2995 usage("isnotrecmaster");
2998 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2999 ctdb->pnn, TIMEOUT(), &recmaster);
3000 if (ret != 0) {
3001 fprintf(stderr, "Failed to get recmaster\n");
3002 return ret;
3005 if (recmaster != ctdb->pnn) {
3006 printf("this node is not the recmaster\n");
3007 return 1;
3010 printf("this node is the recmaster\n");
3011 return 0;
3014 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3015 int argc, const char **argv)
3017 struct ctdb_addr_info addr_info;
3018 int ret;
3020 if (argc != 2) {
3021 usage("gratarp");
3024 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
3025 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3026 return 1;
3028 addr_info.iface = argv[1];
3030 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3031 ctdb->cmd_pnn, TIMEOUT(),
3032 &addr_info);
3033 if (ret != 0) {
3034 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3035 ctdb->cmd_pnn);
3036 return ret;
3039 return 0;
3042 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3043 int argc, const char **argv)
3045 ctdb_sock_addr src, dst;
3046 int ret;
3048 if (argc != 0 && argc != 2) {
3049 usage("tickle");
3052 if (argc == 0) {
3053 struct ctdb_connection *clist;
3054 int count;
3055 int i, num_failed;
3057 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3058 if (ret != 0) {
3059 return ret;
3062 num_failed = 0;
3063 for (i=0; i<count; i++) {
3064 ret = ctdb_sys_send_tcp(&clist[i].src,
3065 &clist[i].dst,
3066 0, 0, 0);
3067 if (ret != 0) {
3068 num_failed += 1;
3072 TALLOC_FREE(clist);
3074 if (num_failed > 0) {
3075 fprintf(stderr, "Failed to send %d tickles\n",
3076 num_failed);
3077 return 1;
3080 return 0;
3084 if (! parse_ip_port(argv[0], &src)) {
3085 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3086 return 1;
3089 if (! parse_ip_port(argv[1], &dst)) {
3090 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3091 return 1;
3094 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3095 if (ret != 0) {
3096 fprintf(stderr, "Failed to send tickle ack\n");
3097 return ret;
3100 return 0;
3103 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3104 int argc, const char **argv)
3106 ctdb_sock_addr addr;
3107 struct ctdb_tickle_list *tickles;
3108 unsigned port = 0;
3109 int ret, i;
3111 if (argc < 1 || argc > 2) {
3112 usage("gettickles");
3115 if (argc == 2) {
3116 port = strtoul(argv[1], NULL, 10);
3119 if (! parse_ip(argv[0], NULL, port, &addr)) {
3120 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3121 return 1;
3124 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3125 ctdb->cmd_pnn, TIMEOUT(), &addr,
3126 &tickles);
3127 if (ret != 0) {
3128 fprintf(stderr, "Failed to get list of connections\n");
3129 return ret;
3132 if (options.machinereadable) {
3133 printf("%s%s%s%s%s%s%s%s%s\n",
3134 options.sep,
3135 "Source IP", options.sep,
3136 "Port", options.sep,
3137 "Destiation IP", options.sep,
3138 "Port", options.sep);
3139 for (i=0; i<tickles->num; i++) {
3140 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3141 ctdb_sock_addr_to_string(
3142 mem_ctx, &tickles->conn[i].src),
3143 options.sep,
3144 ntohs(tickles->conn[i].src.ip.sin_port),
3145 options.sep,
3146 ctdb_sock_addr_to_string(
3147 mem_ctx, &tickles->conn[i].dst),
3148 options.sep,
3149 ntohs(tickles->conn[i].dst.ip.sin_port),
3150 options.sep);
3152 } else {
3153 printf("Connections for IP: %s\n",
3154 ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
3155 printf("Num connections: %u\n", tickles->num);
3156 for (i=0; i<tickles->num; i++) {
3157 printf("SRC: %s:%u DST: %s:%u\n",
3158 ctdb_sock_addr_to_string(
3159 mem_ctx, &tickles->conn[i].src),
3160 ntohs(tickles->conn[i].src.ip.sin_port),
3161 ctdb_sock_addr_to_string(
3162 mem_ctx, &tickles->conn[i].dst),
3163 ntohs(tickles->conn[i].dst.ip.sin_port));
3167 talloc_free(tickles);
3168 return 0;
3171 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3172 struct ctdb_connection *conn);
3174 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3176 struct process_clist_state {
3177 struct ctdb_connection *clist;
3178 int count;
3179 int num_failed, num_total;
3180 clist_reply_func reply_func;
3183 static void process_clist_done(struct tevent_req *subreq);
3185 static struct tevent_req *process_clist_send(
3186 TALLOC_CTX *mem_ctx,
3187 struct ctdb_context *ctdb,
3188 struct ctdb_connection *clist,
3189 int count,
3190 clist_request_func request_func,
3191 clist_reply_func reply_func)
3193 struct tevent_req *req, *subreq;
3194 struct process_clist_state *state;
3195 struct ctdb_req_control request;
3196 int i;
3198 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3199 if (req == NULL) {
3200 return NULL;
3203 state->clist = clist;
3204 state->count = count;
3205 state->reply_func = reply_func;
3207 for (i=0; i<count; i++) {
3208 request_func(&request, &clist[i]);
3209 subreq = ctdb_client_control_send(state, ctdb->ev,
3210 ctdb->client, ctdb->cmd_pnn,
3211 TIMEOUT(), &request);
3212 if (tevent_req_nomem(subreq, req)) {
3213 return tevent_req_post(req, ctdb->ev);
3215 tevent_req_set_callback(subreq, process_clist_done, req);
3218 return req;
3221 static void process_clist_done(struct tevent_req *subreq)
3223 struct tevent_req *req = tevent_req_callback_data(
3224 subreq, struct tevent_req);
3225 struct process_clist_state *state = tevent_req_data(
3226 req, struct process_clist_state);
3227 struct ctdb_reply_control *reply;
3228 int ret;
3229 bool status;
3231 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3232 TALLOC_FREE(subreq);
3233 if (! status) {
3234 state->num_failed += 1;
3235 goto done;
3238 ret = state->reply_func(reply);
3239 if (ret != 0) {
3240 state->num_failed += 1;
3241 goto done;
3244 done:
3245 state->num_total += 1;
3246 if (state->num_total == state->count) {
3247 tevent_req_done(req);
3251 static int process_clist_recv(struct tevent_req *req)
3253 struct process_clist_state *state = tevent_req_data(
3254 req, struct process_clist_state);
3256 return state->num_failed;
3259 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3260 int argc, const char **argv)
3262 struct ctdb_connection conn;
3263 int ret;
3265 if (argc != 0 && argc != 2) {
3266 usage("addtickle");
3269 if (argc == 0) {
3270 struct ctdb_connection *clist;
3271 struct tevent_req *req;
3272 int count;
3274 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3275 if (ret != 0) {
3276 return ret;
3278 if (count == 0) {
3279 return 0;
3282 req = process_clist_send(mem_ctx, ctdb, clist, count,
3283 ctdb_req_control_tcp_add_delayed_update,
3284 ctdb_reply_control_tcp_add_delayed_update);
3285 if (req == NULL) {
3286 talloc_free(clist);
3287 return ENOMEM;
3290 tevent_req_poll(req, ctdb->ev);
3291 talloc_free(clist);
3293 ret = process_clist_recv(req);
3294 if (ret != 0) {
3295 fprintf(stderr, "Failed to add %d tickles\n", ret);
3296 return 1;
3299 return 0;
3302 if (! parse_ip_port(argv[0], &conn.src)) {
3303 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3304 return 1;
3306 if (! parse_ip_port(argv[1], &conn.dst)) {
3307 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3308 return 1;
3311 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3312 ctdb->client, ctdb->cmd_pnn,
3313 TIMEOUT(), &conn);
3314 if (ret != 0) {
3315 fprintf(stderr, "Failed to register connection\n");
3316 return ret;
3319 return 0;
3322 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3323 int argc, const char **argv)
3325 struct ctdb_connection conn;
3326 int ret;
3328 if (argc != 0 && argc != 2) {
3329 usage("deltickle");
3332 if (argc == 0) {
3333 struct ctdb_connection *clist;
3334 struct tevent_req *req;
3335 int count;
3337 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3338 if (ret != 0) {
3339 return ret;
3341 if (count == 0) {
3342 return 0;
3345 req = process_clist_send(mem_ctx, ctdb, clist, count,
3346 ctdb_req_control_tcp_remove,
3347 ctdb_reply_control_tcp_remove);
3348 if (req == NULL) {
3349 talloc_free(clist);
3350 return ENOMEM;
3353 tevent_req_poll(req, ctdb->ev);
3354 talloc_free(clist);
3356 ret = process_clist_recv(req);
3357 if (ret != 0) {
3358 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3359 return 1;
3362 return 0;
3365 if (! parse_ip_port(argv[0], &conn.src)) {
3366 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3367 return 1;
3369 if (! parse_ip_port(argv[1], &conn.dst)) {
3370 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3371 return 1;
3374 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3375 ctdb->cmd_pnn, TIMEOUT(), &conn);
3376 if (ret != 0) {
3377 fprintf(stderr, "Failed to unregister connection\n");
3378 return ret;
3381 return 0;
3384 static int control_check_srvids(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3385 int argc, const char **argv)
3387 uint64_t *srvid;
3388 uint8_t *result;
3389 int ret, i;
3391 if (argc == 0) {
3392 usage("check_srvids");
3395 srvid = talloc_array(mem_ctx, uint64_t, argc);
3396 if (srvid == NULL) {
3397 fprintf(stderr, "Memory allocation error\n");
3398 return 1;
3401 for (i=0; i<argc; i++) {
3402 srvid[i] = strtoull(argv[i], NULL, 0);
3405 ret = ctdb_ctrl_check_srvids(mem_ctx, ctdb->ev, ctdb->client,
3406 ctdb->cmd_pnn, TIMEOUT(), srvid, argc,
3407 &result);
3408 if (ret != 0) {
3409 fprintf(stderr, "Failed to check srvids on node %u\n",
3410 ctdb->cmd_pnn);
3411 return ret;
3414 for (i=0; i<argc; i++) {
3415 printf("SRVID 0x%" PRIx64 " %s\n", srvid[i],
3416 (result[i] ? "exists" : "does not exist"));
3419 return 0;
3422 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3423 int argc, const char **argv)
3425 struct ctdb_node_map *nodemap;
3426 int i;
3428 if (argc != 0) {
3429 usage("listnodes");
3432 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3433 if (nodemap == NULL) {
3434 return 1;
3437 for (i=0; i<nodemap->num; i++) {
3438 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3439 continue;
3442 if (options.machinereadable) {
3443 printf("%s%u%s%s%s\n", options.sep,
3444 nodemap->node[i].pnn, options.sep,
3445 ctdb_sock_addr_to_string(
3446 mem_ctx, &nodemap->node[i].addr),
3447 options.sep);
3448 } else {
3449 printf("%s\n",
3450 ctdb_sock_addr_to_string(
3451 mem_ctx, &nodemap->node[i].addr));
3455 return 0;
3458 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3459 struct ctdb_node_map *nodemap2)
3461 int i;
3463 if (nodemap1->num != nodemap2->num) {
3464 return false;
3467 for (i=0; i<nodemap1->num; i++) {
3468 struct ctdb_node_and_flags *n1, *n2;
3470 n1 = &nodemap1->node[i];
3471 n2 = &nodemap2->node[i];
3473 if ((n1->pnn != n2->pnn) ||
3474 (n1->flags != n2->flags) ||
3475 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3476 return false;
3480 return true;
3483 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3484 struct ctdb_node_map *nm,
3485 struct ctdb_node_map *fnm,
3486 bool *reload)
3488 int i;
3489 bool check_failed = false;
3491 *reload = false;
3493 for (i=0; i<nm->num; i++) {
3494 if (i >= fnm->num) {
3495 fprintf(stderr,
3496 "Node %u (%s) missing from nodes file\n",
3497 nm->node[i].pnn,
3498 ctdb_sock_addr_to_string(
3499 mem_ctx, &nm->node[i].addr));
3500 check_failed = true;
3501 continue;
3503 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3504 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3505 /* Node remains deleted */
3506 continue;
3509 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3510 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3511 /* Node not newly nor previously deleted */
3512 if (! ctdb_same_ip(&nm->node[i].addr,
3513 &fnm->node[i].addr)) {
3514 fprintf(stderr,
3515 "Node %u has changed IP address"
3516 " (was %s, now %s)\n",
3517 nm->node[i].pnn,
3518 ctdb_sock_addr_to_string(
3519 mem_ctx, &nm->node[i].addr),
3520 ctdb_sock_addr_to_string(
3521 mem_ctx, &fnm->node[i].addr));
3522 check_failed = true;
3523 } else {
3524 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3525 fprintf(stderr,
3526 "WARNING: Node %u is disconnected."
3527 " You MUST fix this node manually!\n",
3528 nm->node[i].pnn);
3531 continue;
3534 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3535 /* Node is being deleted */
3536 printf("Node %u is DELETED\n", nm->node[i].pnn);
3537 *reload = true;
3538 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3539 fprintf(stderr,
3540 "ERROR: Node %u is still connected\n",
3541 nm->node[i].pnn);
3542 check_failed = true;
3544 continue;
3547 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3548 /* Node was previously deleted */
3549 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3550 *reload = true;
3554 if (check_failed) {
3555 fprintf(stderr,
3556 "ERROR: Nodes will not be reloaded due to previous error\n");
3557 return 1;
3560 /* Leftover nodes in file are NEW */
3561 for (; i < fnm->num; i++) {
3562 printf("Node %u is NEW\n", fnm->node[i].pnn);
3563 *reload = true;
3566 return 0;
3569 struct disable_recoveries_state {
3570 uint32_t *pnn_list;
3571 int node_count;
3572 bool *reply;
3573 int status;
3574 bool done;
3577 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3578 void *private_data)
3580 struct disable_recoveries_state *state =
3581 (struct disable_recoveries_state *)private_data;
3582 int ret, i;
3584 if (data.dsize != sizeof(int)) {
3585 /* Ignore packet */
3586 return;
3589 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3590 ret = *(int *)data.dptr;
3591 if (ret < 0) {
3592 state->status = ret;
3593 state->done = true;
3594 return;
3596 for (i=0; i<state->node_count; i++) {
3597 if (state->pnn_list[i] == ret) {
3598 state->reply[i] = true;
3599 break;
3603 state->done = true;
3604 for (i=0; i<state->node_count; i++) {
3605 if (! state->reply[i]) {
3606 state->done = false;
3607 break;
3612 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3613 uint32_t timeout, uint32_t *pnn_list, int count)
3615 struct ctdb_disable_message disable = { 0 };
3616 struct disable_recoveries_state state;
3617 int ret, i;
3619 disable.pnn = ctdb->pnn;
3620 disable.srvid = next_srvid(ctdb);
3621 disable.timeout = timeout;
3623 state.pnn_list = pnn_list;
3624 state.node_count = count;
3625 state.done = false;
3626 state.status = 0;
3627 state.reply = talloc_zero_array(mem_ctx, bool, count);
3628 if (state.reply == NULL) {
3629 return ENOMEM;
3632 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3633 disable.srvid,
3634 disable_recoveries_handler,
3635 &state);
3636 if (ret != 0) {
3637 return ret;
3640 for (i=0; i<count; i++) {
3641 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3642 ctdb->client,
3643 pnn_list[i],
3644 &disable);
3645 if (ret != 0) {
3646 goto fail;
3650 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3651 if (ret == ETIME) {
3652 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3653 } else {
3654 ret = (state.status >= 0 ? 0 : 1);
3657 fail:
3658 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3659 disable.srvid, &state);
3660 return ret;
3663 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3664 int argc, const char **argv)
3666 struct ctdb_node_map *nodemap = NULL;
3667 struct ctdb_node_map *file_nodemap;
3668 struct ctdb_node_map *remote_nodemap;
3669 struct ctdb_req_control request;
3670 struct ctdb_reply_control **reply;
3671 bool reload;
3672 int ret, i;
3673 uint32_t *pnn_list;
3674 int count;
3676 nodemap = get_nodemap(ctdb, false);
3677 if (nodemap == NULL) {
3678 return 1;
3681 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3682 if (file_nodemap == NULL) {
3683 return 1;
3686 for (i=0; i<nodemap->num; i++) {
3687 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3688 continue;
3691 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3692 nodemap->node[i].pnn, TIMEOUT(),
3693 &remote_nodemap);
3694 if (ret != 0) {
3695 fprintf(stderr,
3696 "ERROR: Failed to get nodes file from node %u\n",
3697 nodemap->node[i].pnn);
3698 return ret;
3701 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3702 fprintf(stderr,
3703 "ERROR: Nodes file on node %u differs"
3704 " from current node (%u)\n",
3705 nodemap->node[i].pnn, ctdb->pnn);
3706 return 1;
3710 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3711 if (ret != 0) {
3712 return ret;
3715 if (! reload) {
3716 fprintf(stderr, "No change in nodes file,"
3717 " skipping unnecessary reload\n");
3718 return 0;
3721 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3722 mem_ctx, &pnn_list);
3723 if (count <= 0) {
3724 fprintf(stderr, "Memory allocation error\n");
3725 return 1;
3728 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3729 pnn_list, count);
3730 if (ret != 0) {
3731 fprintf(stderr, "Failed to disable recoveries\n");
3732 return ret;
3735 ctdb_req_control_reload_nodes_file(&request);
3736 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3737 pnn_list, count, TIMEOUT(),
3738 &request, NULL, &reply);
3739 if (ret != 0) {
3740 bool failed = false;
3742 for (i=0; i<count; i++) {
3743 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3744 if (ret != 0) {
3745 fprintf(stderr,
3746 "Node %u failed to reload nodes\n",
3747 pnn_list[i]);
3748 failed = true;
3751 if (failed) {
3752 fprintf(stderr,
3753 "You MUST fix failed nodes manually!\n");
3757 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3758 if (ret != 0) {
3759 fprintf(stderr, "Failed to enable recoveries\n");
3760 return ret;
3763 return 0;
3766 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3767 ctdb_sock_addr *addr, uint32_t pnn)
3769 struct ctdb_public_ip_list *pubip_list;
3770 struct ctdb_public_ip pubip;
3771 struct ctdb_node_map *nodemap;
3772 struct ctdb_req_control request;
3773 uint32_t *pnn_list;
3774 int ret, i, count;
3776 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3777 CTDB_BROADCAST_CONNECTED,
3778 2*options.timelimit);
3779 if (ret != 0) {
3780 fprintf(stderr, "Failed to disable IP check\n");
3781 return ret;
3784 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3785 pnn, TIMEOUT(), false, &pubip_list);
3786 if (ret != 0) {
3787 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3788 pnn);
3789 return ret;
3792 for (i=0; i<pubip_list->num; i++) {
3793 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3794 break;
3798 if (i == pubip_list->num) {
3799 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3800 pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
3801 return 1;
3804 nodemap = get_nodemap(ctdb, false);
3805 if (nodemap == NULL) {
3806 return 1;
3809 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3810 if (count <= 0) {
3811 fprintf(stderr, "Memory allocation error\n");
3812 return 1;
3815 pubip.pnn = pnn;
3816 pubip.addr = *addr;
3817 ctdb_req_control_release_ip(&request, &pubip);
3819 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3820 pnn_list, count, TIMEOUT(),
3821 &request, NULL, NULL);
3822 if (ret != 0) {
3823 fprintf(stderr, "Failed to release IP on nodes\n");
3824 return ret;
3827 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3828 pnn, TIMEOUT(), &pubip);
3829 if (ret != 0) {
3830 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3831 return ret;
3834 return 0;
3837 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3838 int argc, const char **argv)
3840 ctdb_sock_addr addr;
3841 uint32_t pnn;
3842 int ret, retries = 0;
3844 if (argc != 2) {
3845 usage("moveip");
3848 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3849 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3850 return 1;
3853 pnn = strtoul(argv[1], NULL, 10);
3854 if (pnn == CTDB_UNKNOWN_PNN) {
3855 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3856 return 1;
3859 while (retries < 5) {
3860 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3861 if (ret == 0) {
3862 break;
3865 sleep(3);
3866 retries++;
3869 if (ret != 0) {
3870 fprintf(stderr, "Failed to move IP %s to node %u\n",
3871 argv[0], pnn);
3872 return ret;
3875 return 0;
3878 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3879 uint32_t pnn)
3881 int ret;
3883 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3884 CTDB_BROADCAST_CONNECTED, pnn);
3885 if (ret != 0) {
3886 fprintf(stderr,
3887 "Failed to ask recovery master to distribute IPs\n");
3888 return ret;
3891 return 0;
3894 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3895 int argc, const char **argv)
3897 ctdb_sock_addr addr;
3898 struct ctdb_public_ip_list *pubip_list;
3899 struct ctdb_addr_info addr_info;
3900 unsigned int mask;
3901 int ret, i, retries = 0;
3903 if (argc != 2) {
3904 usage("addip");
3907 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3908 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3909 return 1;
3912 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3913 ctdb->cmd_pnn, TIMEOUT(),
3914 false, &pubip_list);
3915 if (ret != 0) {
3916 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3917 ctdb->cmd_pnn);
3918 return 1;
3921 for (i=0; i<pubip_list->num; i++) {
3922 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3923 fprintf(stderr, "Node already knows about IP %s\n",
3924 ctdb_sock_addr_to_string(mem_ctx, &addr));
3925 return 0;
3929 addr_info.addr = addr;
3930 addr_info.mask = mask;
3931 addr_info.iface = argv[1];
3933 while (retries < 5) {
3934 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3935 ctdb->cmd_pnn, TIMEOUT(),
3936 &addr_info);
3937 if (ret == 0) {
3938 break;
3941 sleep(3);
3942 retries++;
3945 if (ret != 0) {
3946 fprintf(stderr, "Failed to add public IP to node %u."
3947 " Giving up\n", ctdb->cmd_pnn);
3948 return ret;
3951 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3952 if (ret != 0) {
3953 return ret;
3956 return 0;
3959 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3960 int argc, const char **argv)
3962 ctdb_sock_addr addr;
3963 struct ctdb_public_ip_list *pubip_list;
3964 struct ctdb_addr_info addr_info;
3965 int ret, i;
3967 if (argc != 1) {
3968 usage("delip");
3971 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3972 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3973 return 1;
3976 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3977 ctdb->cmd_pnn, TIMEOUT(),
3978 false, &pubip_list);
3979 if (ret != 0) {
3980 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3981 ctdb->cmd_pnn);
3982 return 1;
3985 for (i=0; i<pubip_list->num; i++) {
3986 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3987 break;
3991 if (i == pubip_list->num) {
3992 fprintf(stderr, "Node does not know about IP address %s\n",
3993 ctdb_sock_addr_to_string(mem_ctx, &addr));
3994 return 0;
3997 addr_info.addr = addr;
3998 addr_info.mask = 0;
3999 addr_info.iface = NULL;
4001 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4002 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
4003 if (ret != 0) {
4004 fprintf(stderr, "Failed to delete public IP from node %u\n",
4005 ctdb->cmd_pnn);
4006 return ret;
4009 return 0;
4012 #define DB_VERSION 3
4013 #define MAX_DB_NAME 64
4014 #define MAX_REC_BUFFER_SIZE (100*1000)
4016 struct db_header {
4017 unsigned long version;
4018 time_t timestamp;
4019 unsigned long flags;
4020 unsigned long nbuf;
4021 unsigned long nrec;
4022 char name[MAX_DB_NAME];
4025 struct backup_state {
4026 TALLOC_CTX *mem_ctx;
4027 struct ctdb_rec_buffer *recbuf;
4028 uint32_t db_id;
4029 int fd;
4030 unsigned int nbuf, nrec;
4033 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4034 TDB_DATA key, TDB_DATA data, void *private_data)
4036 struct backup_state *state = (struct backup_state *)private_data;
4037 size_t len;
4038 int ret;
4040 if (state->recbuf == NULL) {
4041 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4042 state->db_id);
4043 if (state->recbuf == NULL) {
4044 return ENOMEM;
4048 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4049 header, key, data);
4050 if (ret != 0) {
4051 return ret;
4054 len = ctdb_rec_buffer_len(state->recbuf);
4055 if (len < MAX_REC_BUFFER_SIZE) {
4056 return 0;
4059 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4060 if (ret != 0) {
4061 fprintf(stderr, "Failed to write records to backup file\n");
4062 return ret;
4065 state->nbuf += 1;
4066 state->nrec += state->recbuf->count;
4067 TALLOC_FREE(state->recbuf);
4069 return 0;
4072 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4073 int argc, const char **argv)
4075 const char *db_name;
4076 struct ctdb_db_context *db;
4077 uint32_t db_id;
4078 uint8_t db_flags;
4079 struct backup_state state;
4080 struct db_header db_hdr;
4081 int fd, ret;
4083 if (argc != 2) {
4084 usage("backupdb");
4087 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4088 return 1;
4091 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4092 db_flags, &db);
4093 if (ret != 0) {
4094 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4095 return ret;
4098 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4099 if (fd == -1) {
4100 ret = errno;
4101 fprintf(stderr, "Failed to open file %s for writing\n",
4102 argv[1]);
4103 return ret;
4106 /* Write empty header first */
4107 ZERO_STRUCT(db_hdr);
4108 ret = write(fd, &db_hdr, sizeof(struct db_header));
4109 if (ret == -1) {
4110 ret = errno;
4111 close(fd);
4112 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4113 return ret;
4116 state.mem_ctx = mem_ctx;
4117 state.recbuf = NULL;
4118 state.fd = fd;
4119 state.nbuf = 0;
4120 state.nrec = 0;
4122 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4123 if (ret != 0) {
4124 fprintf(stderr, "Failed to collect records from DB %s\n",
4125 db_name);
4126 close(fd);
4127 return ret;
4130 if (state.recbuf != NULL) {
4131 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4132 if (ret != 0) {
4133 fprintf(stderr,
4134 "Failed to write records to backup file\n");
4135 close(fd);
4136 return ret;
4139 state.nbuf += 1;
4140 state.nrec += state.recbuf->count;
4141 TALLOC_FREE(state.recbuf);
4144 db_hdr.version = DB_VERSION;
4145 db_hdr.timestamp = time(NULL);
4146 db_hdr.flags = db_flags;
4147 db_hdr.nbuf = state.nbuf;
4148 db_hdr.nrec = state.nrec;
4149 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4151 lseek(fd, 0, SEEK_SET);
4152 ret = write(fd, &db_hdr, sizeof(struct db_header));
4153 if (ret == -1) {
4154 ret = errno;
4155 close(fd);
4156 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4157 return ret;
4160 close(fd);
4161 printf("Database backed up to %s\n", argv[1]);
4162 return 0;
4165 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4166 int argc, const char **argv)
4168 const char *db_name = NULL;
4169 struct ctdb_db_context *db;
4170 struct db_header db_hdr;
4171 struct ctdb_node_map *nodemap;
4172 struct ctdb_req_control request;
4173 struct ctdb_reply_control **reply;
4174 struct ctdb_transdb wipedb;
4175 struct ctdb_pulldb_ext pulldb;
4176 struct ctdb_rec_buffer *recbuf;
4177 uint32_t generation;
4178 uint32_t *pnn_list;
4179 char timebuf[128];
4180 int fd, i;
4181 int count, ret;
4183 if (argc < 1 || argc > 2) {
4184 usage("restoredb");
4187 fd = open(argv[0], O_RDONLY, 0600);
4188 if (fd == -1) {
4189 ret = errno;
4190 fprintf(stderr, "Failed to open file %s for reading\n",
4191 argv[0]);
4192 return ret;
4195 if (argc == 2) {
4196 db_name = argv[1];
4199 ret = read(fd, &db_hdr, sizeof(struct db_header));
4200 if (ret == -1) {
4201 ret = errno;
4202 close(fd);
4203 fprintf(stderr, "Failed to read db header from file %s\n",
4204 argv[0]);
4205 return ret;
4207 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4209 if (db_hdr.version != DB_VERSION) {
4210 fprintf(stderr,
4211 "Wrong version of backup file, expected %u, got %lu\n",
4212 DB_VERSION, db_hdr.version);
4213 close(fd);
4214 return EINVAL;
4217 if (db_name == NULL) {
4218 db_name = db_hdr.name;
4221 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4222 localtime(&db_hdr.timestamp));
4223 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4225 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4226 db_hdr.flags, &db);
4227 if (ret != 0) {
4228 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4229 close(fd);
4230 return ret;
4233 nodemap = get_nodemap(ctdb, false);
4234 if (nodemap == NULL) {
4235 fprintf(stderr, "Failed to get nodemap\n");
4236 close(fd);
4237 return ENOMEM;
4240 ret = get_generation(mem_ctx, ctdb, &generation);
4241 if (ret != 0) {
4242 fprintf(stderr, "Failed to get current generation\n");
4243 close(fd);
4244 return ret;
4247 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4248 &pnn_list);
4249 if (count <= 0) {
4250 close(fd);
4251 return ENOMEM;
4254 wipedb.db_id = ctdb_db_id(db);
4255 wipedb.tid = generation;
4257 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4258 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4259 ctdb->client, pnn_list, count,
4260 TIMEOUT(), &request, NULL, NULL);
4261 if (ret != 0) {
4262 goto failed;
4266 ctdb_req_control_db_transaction_start(&request, &wipedb);
4267 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4268 pnn_list, count, TIMEOUT(),
4269 &request, NULL, NULL);
4270 if (ret != 0) {
4271 goto failed;
4274 ctdb_req_control_wipe_database(&request, &wipedb);
4275 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4276 pnn_list, count, TIMEOUT(),
4277 &request, NULL, NULL);
4278 if (ret != 0) {
4279 goto failed;
4282 pulldb.db_id = ctdb_db_id(db);
4283 pulldb.lmaster = 0;
4284 pulldb.srvid = SRVID_CTDB_PUSHDB;
4286 ctdb_req_control_db_push_start(&request, &pulldb);
4287 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4288 pnn_list, count, TIMEOUT(),
4289 &request, NULL, NULL);
4290 if (ret != 0) {
4291 goto failed;
4294 for (i=0; i<db_hdr.nbuf; i++) {
4295 struct ctdb_req_message message;
4296 TDB_DATA data;
4298 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4299 if (ret != 0) {
4300 goto failed;
4303 data.dsize = ctdb_rec_buffer_len(recbuf);
4304 data.dptr = talloc_size(mem_ctx, data.dsize);
4305 if (data.dptr == NULL) {
4306 goto failed;
4309 ctdb_rec_buffer_push(recbuf, data.dptr);
4311 message.srvid = pulldb.srvid;
4312 message.data.data = data;
4314 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4315 ctdb->client,
4316 pnn_list, count,
4317 &message, NULL);
4318 if (ret != 0) {
4319 goto failed;
4322 talloc_free(recbuf);
4323 talloc_free(data.dptr);
4326 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4327 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4328 pnn_list, count, TIMEOUT(),
4329 &request, NULL, &reply);
4330 if (ret != 0) {
4331 goto failed;
4334 for (i=0; i<count; i++) {
4335 uint32_t num_records;
4337 ret = ctdb_reply_control_db_push_confirm(reply[i],
4338 &num_records);
4339 if (ret != 0) {
4340 fprintf(stderr, "Invalid response from node %u\n",
4341 pnn_list[i]);
4342 goto failed;
4345 if (num_records != db_hdr.nrec) {
4346 fprintf(stderr, "Node %u received %u of %lu records\n",
4347 pnn_list[i], num_records, db_hdr.nrec);
4348 goto failed;
4352 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4353 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4354 pnn_list, count, TIMEOUT(),
4355 &request, NULL, NULL);
4356 if (ret != 0) {
4357 goto failed;
4360 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4361 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4362 pnn_list, count, TIMEOUT(),
4363 &request, NULL, NULL);
4364 if (ret != 0) {
4365 goto failed;
4368 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4369 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4370 ctdb->client, pnn_list, count,
4371 TIMEOUT(), &request, NULL, NULL);
4372 if (ret != 0) {
4373 goto failed;
4376 printf("Database %s restored\n", db_name);
4377 close(fd);
4378 return 0;
4381 failed:
4382 close(fd);
4383 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4384 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4385 return ret;
4388 struct dumpdbbackup_state {
4389 ctdb_rec_parser_func_t parser;
4390 struct dump_record_state sub_state;
4393 static int dumpdbbackup_handler(uint32_t reqid,
4394 struct ctdb_ltdb_header *header,
4395 TDB_DATA key, TDB_DATA data,
4396 void *private_data)
4398 struct dumpdbbackup_state *state =
4399 (struct dumpdbbackup_state *)private_data;
4400 struct ctdb_ltdb_header hdr;
4401 int ret;
4403 ret = ctdb_ltdb_header_extract(&data, &hdr);
4404 if (ret != 0) {
4405 return ret;
4408 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4411 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4412 int argc, const char **argv)
4414 struct db_header db_hdr;
4415 char timebuf[128];
4416 struct dumpdbbackup_state state;
4417 int fd, ret, i;
4419 if (argc != 1) {
4420 usage("dumpbackup");
4423 fd = open(argv[0], O_RDONLY, 0600);
4424 if (fd == -1) {
4425 ret = errno;
4426 fprintf(stderr, "Failed to open file %s for reading\n",
4427 argv[0]);
4428 return ret;
4431 ret = read(fd, &db_hdr, sizeof(struct db_header));
4432 if (ret == -1) {
4433 ret = errno;
4434 close(fd);
4435 fprintf(stderr, "Failed to read db header from file %s\n",
4436 argv[0]);
4437 return ret;
4439 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4441 if (db_hdr.version != DB_VERSION) {
4442 fprintf(stderr,
4443 "Wrong version of backup file, expected %u, got %lu\n",
4444 DB_VERSION, db_hdr.version);
4445 close(fd);
4446 return EINVAL;
4449 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4450 localtime(&db_hdr.timestamp));
4451 printf("Dumping database %s from backup @ %s\n",
4452 db_hdr.name, timebuf);
4454 state.parser = dump_record;
4455 state.sub_state.count = 0;
4457 for (i=0; i<db_hdr.nbuf; i++) {
4458 struct ctdb_rec_buffer *recbuf;
4460 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4461 if (ret != 0) {
4462 fprintf(stderr, "Failed to read records\n");
4463 close(fd);
4464 return ret;
4467 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4468 &state);
4469 if (ret != 0) {
4470 fprintf(stderr, "Failed to dump records\n");
4471 close(fd);
4472 return ret;
4476 close(fd);
4477 printf("Dumped %u record(s)\n", state.sub_state.count);
4478 return 0;
4481 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4482 int argc, const char **argv)
4484 const char *db_name;
4485 struct ctdb_db_context *db;
4486 uint32_t db_id;
4487 uint8_t db_flags;
4488 struct ctdb_node_map *nodemap;
4489 struct ctdb_req_control request;
4490 struct ctdb_transdb wipedb;
4491 uint32_t generation;
4492 uint32_t *pnn_list;
4493 int count, ret;
4495 if (argc != 1) {
4496 usage("wipedb");
4499 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4500 return 1;
4503 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4504 db_flags, &db);
4505 if (ret != 0) {
4506 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4507 return ret;
4510 nodemap = get_nodemap(ctdb, false);
4511 if (nodemap == NULL) {
4512 fprintf(stderr, "Failed to get nodemap\n");
4513 return ENOMEM;
4516 ret = get_generation(mem_ctx, ctdb, &generation);
4517 if (ret != 0) {
4518 fprintf(stderr, "Failed to get current generation\n");
4519 return ret;
4522 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4523 &pnn_list);
4524 if (count <= 0) {
4525 return ENOMEM;
4528 ctdb_req_control_db_freeze(&request, db_id);
4529 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4530 ctdb->client, pnn_list, count,
4531 TIMEOUT(), &request, NULL, NULL);
4532 if (ret != 0) {
4533 goto failed;
4536 wipedb.db_id = db_id;
4537 wipedb.tid = generation;
4539 ctdb_req_control_db_transaction_start(&request, &wipedb);
4540 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4541 pnn_list, count, TIMEOUT(),
4542 &request, NULL, NULL);
4543 if (ret != 0) {
4544 goto failed;
4547 ctdb_req_control_wipe_database(&request, &wipedb);
4548 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4549 pnn_list, count, TIMEOUT(),
4550 &request, NULL, NULL);
4551 if (ret != 0) {
4552 goto failed;
4555 ctdb_req_control_db_set_healthy(&request, db_id);
4556 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4557 pnn_list, count, TIMEOUT(),
4558 &request, NULL, NULL);
4559 if (ret != 0) {
4560 goto failed;
4563 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4564 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4565 pnn_list, count, TIMEOUT(),
4566 &request, NULL, NULL);
4567 if (ret != 0) {
4568 goto failed;
4571 ctdb_req_control_db_thaw(&request, db_id);
4572 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4573 ctdb->client, pnn_list, count,
4574 TIMEOUT(), &request, NULL, NULL);
4575 if (ret != 0) {
4576 goto failed;
4579 printf("Database %s wiped\n", db_name);
4580 return 0;
4583 failed:
4584 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4585 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4586 return ret;
4589 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4590 int argc, const char **argv)
4592 uint32_t recmaster;
4593 int ret;
4595 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4596 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4597 if (ret != 0) {
4598 return ret;
4601 printf("%u\n", recmaster);
4602 return 0;
4605 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4606 int argc, const char **argv)
4608 char *t, *event_helper = NULL;
4609 char *eventd_socket = NULL;
4610 const char **new_argv;
4611 int i;
4613 t = getenv("CTDB_EVENT_HELPER");
4614 if (t != NULL) {
4615 event_helper = talloc_strdup(mem_ctx, t);
4616 } else {
4617 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb_event",
4618 CTDB_HELPER_BINDIR);
4621 if (event_helper == NULL) {
4622 fprintf(stderr, "Unable to set event daemon helper\n");
4623 return 1;
4626 t = getenv("CTDB_SOCKET");
4627 if (t != NULL) {
4628 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4629 dirname(t));
4630 } else {
4631 eventd_socket = talloc_asprintf(mem_ctx, "%s/eventd.sock",
4632 CTDB_RUNDIR);
4635 if (eventd_socket == NULL) {
4636 fprintf(stderr, "Unable to set event daemon socket\n");
4637 return 1;
4640 new_argv = talloc_array(mem_ctx, const char *, argc + 1);
4641 if (new_argv == NULL) {
4642 fprintf(stderr, "Memory allocation error\n");
4643 return 1;
4646 new_argv[0] = eventd_socket;
4647 for (i=0; i<argc; i++) {
4648 new_argv[i+1] = argv[i];
4651 return run_helper(mem_ctx, "event daemon helper", event_helper,
4652 argc+1, new_argv);
4655 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4656 int argc, const char **argv)
4658 const char *new_argv[3];
4660 if (argc > 1) {
4661 usage("scriptstatus");
4664 new_argv[0] = "status";
4665 new_argv[1] = (argc == 0) ? "monitor" : argv[0];
4666 new_argv[2] = NULL;
4668 (void) control_event(mem_ctx, ctdb, 2, new_argv);
4669 return 0;
4672 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4673 int argc, const char **argv)
4675 char *t, *natgw_helper = NULL;
4677 if (argc != 1) {
4678 usage("natgw");
4681 t = getenv("CTDB_NATGW_HELPER");
4682 if (t != NULL) {
4683 natgw_helper = talloc_strdup(mem_ctx, t);
4684 } else {
4685 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4686 CTDB_HELPER_BINDIR);
4689 if (natgw_helper == NULL) {
4690 fprintf(stderr, "Unable to set NAT gateway helper\n");
4691 return 1;
4694 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4695 argc, argv);
4698 static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4699 int argc, const char **argv)
4701 char *t, *natgw_helper = NULL;
4702 const char *cmd_argv[] = { "natgwlist", NULL };
4704 if (argc != 0) {
4705 usage("natgwlist");
4708 t = getenv("CTDB_NATGW_HELPER");
4709 if (t != NULL) {
4710 natgw_helper = talloc_strdup(mem_ctx, t);
4711 } else {
4712 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4713 CTDB_HELPER_BINDIR);
4716 if (natgw_helper == NULL) {
4717 fprintf(stderr, "Unable to set NAT gateway helper\n");
4718 return 1;
4721 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4722 1, cmd_argv);
4726 * Find the PNN of the current node
4727 * discover the pnn by loading the nodes file and try to bind
4728 * to all addresses one at a time until the ip address is found.
4730 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4732 struct ctdb_node_map *nodemap;
4733 int i;
4735 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4736 if (nodemap == NULL) {
4737 return false;
4740 for (i=0; i<nodemap->num; i++) {
4741 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4742 continue;
4744 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4745 if (pnn != NULL) {
4746 *pnn = nodemap->node[i].pnn;
4748 talloc_free(nodemap);
4749 return true;
4753 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4754 talloc_free(nodemap);
4755 return false;
4758 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4759 int argc, const char **argv)
4761 const char *reclock;
4762 int ret;
4764 if (argc != 0) {
4765 usage("getreclock");
4768 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4769 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4770 if (ret != 0) {
4771 return ret;
4774 if (reclock != NULL) {
4775 printf("%s\n", reclock);
4778 return 0;
4781 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4782 struct ctdb_context *ctdb,
4783 int argc, const char **argv)
4785 uint32_t lmasterrole = 0;
4786 int ret;
4788 if (argc != 1) {
4789 usage("setlmasterrole");
4792 if (strcmp(argv[0], "on") == 0) {
4793 lmasterrole = 1;
4794 } else if (strcmp(argv[0], "off") == 0) {
4795 lmasterrole = 0;
4796 } else {
4797 usage("setlmasterrole");
4800 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4801 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4802 if (ret != 0) {
4803 return ret;
4806 return 0;
4809 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4810 struct ctdb_context *ctdb,
4811 int argc, const char **argv)
4813 uint32_t recmasterrole = 0;
4814 int ret;
4816 if (argc != 1) {
4817 usage("setrecmasterrole");
4820 if (strcmp(argv[0], "on") == 0) {
4821 recmasterrole = 1;
4822 } else if (strcmp(argv[0], "off") == 0) {
4823 recmasterrole = 0;
4824 } else {
4825 usage("setrecmasterrole");
4828 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4829 ctdb->cmd_pnn, TIMEOUT(),
4830 recmasterrole);
4831 if (ret != 0) {
4832 return ret;
4835 return 0;
4838 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4839 struct ctdb_context *ctdb,
4840 int argc, const char **argv)
4842 uint32_t db_id;
4843 uint8_t db_flags;
4844 int ret;
4846 if (argc != 1) {
4847 usage("setdbreadonly");
4850 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4851 return 1;
4854 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4855 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4856 return 1;
4859 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4860 ctdb->cmd_pnn, TIMEOUT(), db_id);
4861 if (ret != 0) {
4862 return ret;
4865 return 0;
4868 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4869 int argc, const char **argv)
4871 uint32_t db_id;
4872 uint8_t db_flags;
4873 int ret;
4875 if (argc != 1) {
4876 usage("setdbsticky");
4879 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4880 return 1;
4883 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4884 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4885 return 1;
4888 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4889 ctdb->cmd_pnn, TIMEOUT(), db_id);
4890 if (ret != 0) {
4891 return ret;
4894 return 0;
4897 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4898 int argc, const char **argv)
4900 const char *db_name;
4901 struct ctdb_db_context *db;
4902 struct ctdb_transaction_handle *h;
4903 uint8_t db_flags;
4904 TDB_DATA key, data;
4905 int ret;
4907 if (argc < 2 || argc > 3) {
4908 usage("pfetch");
4911 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4912 return 1;
4915 if (! (db_flags &
4916 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4917 fprintf(stderr, "Transactions not supported on DB %s\n",
4918 db_name);
4919 return 1;
4922 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4923 db_flags, &db);
4924 if (ret != 0) {
4925 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4926 return ret;
4929 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4930 if (ret != 0) {
4931 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4932 return ret;
4935 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4936 TIMEOUT(), db, true, &h);
4937 if (ret != 0) {
4938 fprintf(stderr, "Failed to start transaction on db %s\n",
4939 db_name);
4940 return ret;
4943 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4944 if (ret != 0) {
4945 fprintf(stderr, "Failed to read record for key %s\n",
4946 argv[1]);
4947 ctdb_transaction_cancel(h);
4948 return ret;
4951 printf("%.*s\n", (int)data.dsize, data.dptr);
4953 ctdb_transaction_cancel(h);
4954 return 0;
4957 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4958 int argc, const char **argv)
4960 const char *db_name;
4961 struct ctdb_db_context *db;
4962 struct ctdb_transaction_handle *h;
4963 uint8_t db_flags;
4964 TDB_DATA key, data;
4965 int ret;
4967 if (argc != 3) {
4968 usage("pstore");
4971 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4972 return 1;
4975 if (! (db_flags &
4976 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4977 fprintf(stderr, "Transactions not supported on DB %s\n",
4978 db_name);
4979 return 1;
4982 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4983 db_flags, &db);
4984 if (ret != 0) {
4985 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4986 return ret;
4989 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4990 if (ret != 0) {
4991 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4992 return ret;
4995 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4996 if (ret != 0) {
4997 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4998 return ret;
5001 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5002 TIMEOUT(), db, false, &h);
5003 if (ret != 0) {
5004 fprintf(stderr, "Failed to start transaction on db %s\n",
5005 db_name);
5006 return ret;
5009 ret = ctdb_transaction_store_record(h, key, data);
5010 if (ret != 0) {
5011 fprintf(stderr, "Failed to store record for key %s\n",
5012 argv[1]);
5013 ctdb_transaction_cancel(h);
5014 return ret;
5017 ret = ctdb_transaction_commit(h);
5018 if (ret != 0) {
5019 fprintf(stderr, "Failed to commit transaction on db %s\n",
5020 db_name);
5021 ctdb_transaction_cancel(h);
5022 return ret;
5025 return 0;
5028 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5029 int argc, const char **argv)
5031 const char *db_name;
5032 struct ctdb_db_context *db;
5033 struct ctdb_transaction_handle *h;
5034 uint8_t db_flags;
5035 TDB_DATA key;
5036 int ret;
5038 if (argc != 2) {
5039 usage("pdelete");
5042 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5043 return 1;
5046 if (! (db_flags &
5047 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5048 fprintf(stderr, "Transactions not supported on DB %s\n",
5049 db_name);
5050 return 1;
5053 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5054 db_flags, &db);
5055 if (ret != 0) {
5056 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5057 return ret;
5060 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5061 if (ret != 0) {
5062 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5063 return ret;
5066 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5067 TIMEOUT(), db, false, &h);
5068 if (ret != 0) {
5069 fprintf(stderr, "Failed to start transaction on db %s\n",
5070 db_name);
5071 return ret;
5074 ret = ctdb_transaction_delete_record(h, key);
5075 if (ret != 0) {
5076 fprintf(stderr, "Failed to delete record for key %s\n",
5077 argv[1]);
5078 ctdb_transaction_cancel(h);
5079 return ret;
5082 ret = ctdb_transaction_commit(h);
5083 if (ret != 0) {
5084 fprintf(stderr, "Failed to commit transaction on db %s\n",
5085 db_name);
5086 ctdb_transaction_cancel(h);
5087 return ret;
5090 return 0;
5093 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5095 const char *t;
5096 size_t n;
5097 int ret;
5099 *data = tdb_null;
5101 /* Skip whitespace */
5102 n = strspn(*ptr, " \t");
5103 t = *ptr + n;
5105 if (t[0] == '"') {
5106 /* Quoted ASCII string - no wide characters! */
5107 t++;
5108 n = strcspn(t, "\"");
5109 if (t[n] == '"') {
5110 if (n > 0) {
5111 ret = str_to_data(t, n, mem_ctx, data);
5112 if (ret != 0) {
5113 return ret;
5116 *ptr = t + n + 1;
5117 } else {
5118 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5119 return 1;
5121 } else {
5122 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5123 return 1;
5126 return 0;
5129 #define MAX_LINE_SIZE 1024
5131 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5132 TDB_DATA *key, TDB_DATA *value)
5134 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5135 const char *ptr;
5136 int ret;
5138 ptr = fgets(line, MAX_LINE_SIZE, file);
5139 if (ptr == NULL) {
5140 return false;
5143 /* Get key */
5144 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5145 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5146 /* Line Ignored but not EOF */
5147 *key = tdb_null;
5148 return true;
5151 /* Get value */
5152 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5153 if (ret != 0) {
5154 /* Line Ignored but not EOF */
5155 talloc_free(key->dptr);
5156 *key = tdb_null;
5157 return true;
5160 return true;
5163 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5164 int argc, const char **argv)
5166 const char *db_name;
5167 struct ctdb_db_context *db;
5168 struct ctdb_transaction_handle *h;
5169 uint8_t db_flags;
5170 FILE *file;
5171 TDB_DATA key, value;
5172 int ret;
5174 if (argc < 1 || argc > 2) {
5175 usage("ptrans");
5178 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5179 return 1;
5182 if (! (db_flags &
5183 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5184 fprintf(stderr, "Transactions not supported on DB %s\n",
5185 db_name);
5186 return 1;
5189 if (argc == 2) {
5190 file = fopen(argv[1], "r");
5191 if (file == NULL) {
5192 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5193 return 1;
5195 } else {
5196 file = stdin;
5199 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5200 db_flags, &db);
5201 if (ret != 0) {
5202 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5203 goto done;
5206 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5207 TIMEOUT(), db, false, &h);
5208 if (ret != 0) {
5209 fprintf(stderr, "Failed to start transaction on db %s\n",
5210 db_name);
5211 goto done;
5214 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5215 if (key.dsize != 0) {
5216 ret = ctdb_transaction_store_record(h, key, value);
5217 if (ret != 0) {
5218 fprintf(stderr, "Failed to store record\n");
5219 ctdb_transaction_cancel(h);
5220 goto done;
5222 talloc_free(key.dptr);
5223 talloc_free(value.dptr);
5227 ret = ctdb_transaction_commit(h);
5228 if (ret != 0) {
5229 fprintf(stderr, "Failed to commit transaction on db %s\n",
5230 db_name);
5231 ctdb_transaction_cancel(h);
5234 done:
5235 if (file != stdin) {
5236 fclose(file);
5238 return ret;
5241 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5242 int argc, const char **argv)
5244 struct tdb_context *tdb;
5245 TDB_DATA key, data;
5246 struct ctdb_ltdb_header header;
5247 int ret;
5249 if (argc < 2 || argc > 3) {
5250 usage("tfetch");
5253 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5254 if (tdb == NULL) {
5255 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5256 return 1;
5259 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5260 if (ret != 0) {
5261 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5262 tdb_close(tdb);
5263 return ret;
5266 data = tdb_fetch(tdb, key);
5267 if (data.dptr == NULL) {
5268 fprintf(stderr, "No record for key %s\n", argv[1]);
5269 tdb_close(tdb);
5270 return 1;
5273 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5274 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5275 tdb_close(tdb);
5276 return 1;
5279 tdb_close(tdb);
5281 if (argc == 3) {
5282 int fd;
5283 ssize_t nwritten;
5285 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5286 if (fd == -1) {
5287 fprintf(stderr, "Failed to open output file %s\n",
5288 argv[2]);
5289 goto fail;
5292 nwritten = sys_write(fd, data.dptr, data.dsize);
5293 if (nwritten != data.dsize) {
5294 fprintf(stderr, "Failed to write record to file\n");
5295 close(fd);
5296 goto fail;
5299 close(fd);
5302 fail:
5303 ret = ctdb_ltdb_header_extract(&data, &header);
5304 if (ret != 0) {
5305 fprintf(stderr, "Failed to parse header from data\n");
5306 return 1;
5309 dump_ltdb_header(&header);
5310 dump_tdb_data("data", data);
5312 return 0;
5315 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5316 int argc, const char **argv)
5318 struct tdb_context *tdb;
5319 TDB_DATA key, data[2], value;
5320 struct ctdb_ltdb_header header;
5321 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5322 int ret;
5324 if (argc < 3 || argc > 5) {
5325 usage("tstore");
5328 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5329 if (tdb == NULL) {
5330 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5331 return 1;
5334 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5335 if (ret != 0) {
5336 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5337 tdb_close(tdb);
5338 return ret;
5341 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5342 if (ret != 0) {
5343 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5344 tdb_close(tdb);
5345 return ret;
5348 ZERO_STRUCT(header);
5350 if (argc > 3) {
5351 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5353 if (argc > 4) {
5354 header.dmaster = (uint32_t)atol(argv[4]);
5356 if (argc > 5) {
5357 header.flags = (uint32_t)atol(argv[5]);
5360 ctdb_ltdb_header_push(&header, header_buf);
5362 data[0].dsize = ctdb_ltdb_header_len(&header);
5363 data[0].dptr = header_buf;
5365 data[1].dsize = value.dsize;
5366 data[1].dptr = value.dptr;
5368 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5369 if (ret != 0) {
5370 fprintf(stderr, "Failed to write record %s to file %s\n",
5371 argv[1], argv[0]);
5374 tdb_close(tdb);
5376 return ret;
5379 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5380 int argc, const char **argv)
5382 const char *db_name;
5383 struct ctdb_db_context *db;
5384 struct ctdb_record_handle *h;
5385 uint8_t db_flags;
5386 TDB_DATA key, data;
5387 bool readonly = false;
5388 int ret;
5390 if (argc < 2 || argc > 3) {
5391 usage("readkey");
5394 if (argc == 3) {
5395 if (strcmp(argv[2], "readonly") == 0) {
5396 readonly = true;
5397 } else {
5398 usage("readkey");
5402 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5403 return 1;
5406 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5407 fprintf(stderr, "DB %s is not a volatile database\n",
5408 db_name);
5409 return 1;
5412 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5413 db_flags, &db);
5414 if (ret != 0) {
5415 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5416 return ret;
5419 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5420 if (ret != 0) {
5421 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5422 return ret;
5425 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5426 db, key, readonly, &h, NULL, &data);
5427 if (ret != 0) {
5428 fprintf(stderr, "Failed to read record for key %s\n",
5429 argv[1]);
5430 } else {
5431 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5432 (int)data.dsize, data.dptr);
5435 talloc_free(h);
5436 return ret;
5439 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5440 int argc, const char **argv)
5442 const char *db_name;
5443 struct ctdb_db_context *db;
5444 struct ctdb_record_handle *h;
5445 uint8_t db_flags;
5446 TDB_DATA key, data;
5447 int ret;
5449 if (argc != 3) {
5450 usage("writekey");
5453 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5454 return 1;
5457 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5458 fprintf(stderr, "DB %s is not a volatile database\n",
5459 db_name);
5460 return 1;
5463 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5464 db_flags, &db);
5465 if (ret != 0) {
5466 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5467 return ret;
5470 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5471 if (ret != 0) {
5472 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5473 return ret;
5476 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5477 if (ret != 0) {
5478 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5479 return ret;
5482 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5483 db, key, false, &h, NULL, NULL);
5484 if (ret != 0) {
5485 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5486 return ret;
5489 ret = ctdb_store_record(h, data);
5490 if (ret != 0) {
5491 fprintf(stderr, "Failed to store record for key %s\n",
5492 argv[1]);
5495 talloc_free(h);
5496 return ret;
5499 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5500 int argc, const char **argv)
5502 const char *db_name;
5503 struct ctdb_db_context *db;
5504 struct ctdb_record_handle *h;
5505 uint8_t db_flags;
5506 TDB_DATA key, data;
5507 int ret;
5509 if (argc != 2) {
5510 usage("deletekey");
5513 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5514 return 1;
5517 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5518 fprintf(stderr, "DB %s is not a volatile database\n",
5519 db_name);
5520 return 1;
5523 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5524 db_flags, &db);
5525 if (ret != 0) {
5526 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5527 return ret;
5530 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5531 if (ret != 0) {
5532 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5533 return ret;
5536 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5537 db, key, false, &h, NULL, &data);
5538 if (ret != 0) {
5539 fprintf(stderr, "Failed to fetch record for key %s\n",
5540 argv[1]);
5541 return ret;
5544 ret = ctdb_delete_record(h);
5545 if (ret != 0) {
5546 fprintf(stderr, "Failed to delete record for key %s\n",
5547 argv[1]);
5550 talloc_free(h);
5551 return ret;
5554 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5555 int argc, const char **argv)
5557 struct sockaddr_in sin;
5558 unsigned int port;
5559 int s, v;
5560 int ret;
5562 if (argc != 1) {
5563 usage("chktcpport");
5566 port = atoi(argv[0]);
5568 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5569 if (s == -1) {
5570 fprintf(stderr, "Failed to open local socket\n");
5571 return errno;
5574 v = fcntl(s, F_GETFL, 0);
5575 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5576 fprintf(stderr, "Unable to set socket non-blocking\n");
5577 close(s);
5578 return errno;
5581 bzero(&sin, sizeof(sin));
5582 sin.sin_family = AF_INET;
5583 sin.sin_port = htons(port);
5584 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5585 close(s);
5586 if (ret == -1) {
5587 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5588 return errno;
5591 return 0;
5594 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5595 int argc, const char **argv)
5597 uint32_t db_id;
5598 const char *db_name;
5599 uint64_t seqnum;
5600 int ret;
5602 if (argc != 1) {
5603 usage("getdbseqnum");
5606 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5607 return 1;
5610 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5611 ctdb->cmd_pnn, TIMEOUT(), db_id,
5612 &seqnum);
5613 if (ret != 0) {
5614 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5615 db_name);
5616 return ret;
5619 printf("0x%"PRIx64"\n", seqnum);
5620 return 0;
5623 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5624 int argc, const char **argv)
5626 const char *nodestring = NULL;
5627 struct ctdb_node_map *nodemap;
5628 int ret, i;
5629 bool print_hdr = false;
5631 if (argc > 1) {
5632 usage("nodestatus");
5635 if (argc == 1) {
5636 nodestring = argv[0];
5637 if (strcmp(nodestring, "all") == 0) {
5638 print_hdr = true;
5642 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5643 return 1;
5646 if (options.machinereadable) {
5647 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5648 } else {
5649 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5652 ret = 0;
5653 for (i=0; i<nodemap->num; i++) {
5654 ret |= nodemap->node[i].flags;
5657 return ret;
5660 const struct {
5661 const char *name;
5662 uint32_t offset;
5663 } db_stats_fields[] = {
5664 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5665 DBSTATISTICS_FIELD(db_ro_delegations),
5666 DBSTATISTICS_FIELD(db_ro_revokes),
5667 DBSTATISTICS_FIELD(locks.num_calls),
5668 DBSTATISTICS_FIELD(locks.num_current),
5669 DBSTATISTICS_FIELD(locks.num_pending),
5670 DBSTATISTICS_FIELD(locks.num_failed),
5671 DBSTATISTICS_FIELD(db_ro_delegations),
5674 static void print_dbstatistics(const char *db_name,
5675 struct ctdb_db_statistics *s)
5677 int i;
5678 const char *prefix = NULL;
5679 int preflen = 0;
5681 printf("DB Statistics %s\n", db_name);
5683 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5684 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5685 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5686 if (! prefix ||
5687 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5688 prefix = db_stats_fields[i].name;
5689 printf(" %*.*s\n", preflen-1, preflen-1,
5690 db_stats_fields[i].name);
5692 } else {
5693 preflen = 0;
5695 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5696 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5697 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5700 printf(" hop_count_buckets:");
5701 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5702 printf(" %d", s->hop_count_bucket[i]);
5704 printf("\n");
5706 printf(" lock_buckets:");
5707 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5708 printf(" %d", s->locks.buckets[i]);
5710 printf("\n");
5712 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5713 "locks_latency MIN/AVG/MAX",
5714 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5715 s->locks.latency.max, s->locks.latency.num);
5717 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5718 "vacuum_latency MIN/AVG/MAX",
5719 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5720 s->vacuum.latency.max, s->vacuum.latency.num);
5722 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5723 for (i=0; i<s->num_hot_keys; i++) {
5724 int j;
5725 printf(" Count:%d Key:", s->hot_keys[i].count);
5726 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5727 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5729 printf("\n");
5733 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5734 int argc, const char **argv)
5736 uint32_t db_id;
5737 const char *db_name;
5738 struct ctdb_db_statistics *dbstats;
5739 int ret;
5741 if (argc != 1) {
5742 usage("dbstatistics");
5745 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5746 return 1;
5749 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5750 ctdb->cmd_pnn, TIMEOUT(), db_id,
5751 &dbstats);
5752 if (ret != 0) {
5753 fprintf(stderr, "Failed to get statistics for DB %s\n",
5754 db_name);
5755 return ret;
5758 print_dbstatistics(db_name, dbstats);
5759 return 0;
5762 struct disable_takeover_runs_state {
5763 uint32_t *pnn_list;
5764 int node_count;
5765 bool *reply;
5766 int status;
5767 bool done;
5770 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5771 void *private_data)
5773 struct disable_takeover_runs_state *state =
5774 (struct disable_takeover_runs_state *)private_data;
5775 int ret, i;
5777 if (data.dsize != sizeof(int)) {
5778 /* Ignore packet */
5779 return;
5782 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5783 ret = *(int *)data.dptr;
5784 if (ret < 0) {
5785 state->status = ret;
5786 state->done = true;
5787 return;
5789 for (i=0; i<state->node_count; i++) {
5790 if (state->pnn_list[i] == ret) {
5791 state->reply[i] = true;
5792 break;
5796 state->done = true;
5797 for (i=0; i<state->node_count; i++) {
5798 if (! state->reply[i]) {
5799 state->done = false;
5800 break;
5805 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5806 struct ctdb_context *ctdb, uint32_t timeout,
5807 uint32_t *pnn_list, int count)
5809 struct ctdb_disable_message disable = { 0 };
5810 struct disable_takeover_runs_state state;
5811 int ret, i;
5813 disable.pnn = ctdb->pnn;
5814 disable.srvid = next_srvid(ctdb);
5815 disable.timeout = timeout;
5817 state.pnn_list = pnn_list;
5818 state.node_count = count;
5819 state.done = false;
5820 state.status = 0;
5821 state.reply = talloc_zero_array(mem_ctx, bool, count);
5822 if (state.reply == NULL) {
5823 return ENOMEM;
5826 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5827 disable.srvid,
5828 disable_takeover_run_handler,
5829 &state);
5830 if (ret != 0) {
5831 return ret;
5834 for (i=0; i<count; i++) {
5835 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5836 ctdb->client,
5837 pnn_list[i],
5838 &disable);
5839 if (ret != 0) {
5840 goto fail;
5844 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5845 if (ret == ETIME) {
5846 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5847 } else {
5848 ret = (state.status >= 0 ? 0 : 1);
5851 fail:
5852 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5853 disable.srvid, &state);
5854 return ret;
5857 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5858 int argc, const char **argv)
5860 const char *nodestring = NULL;
5861 struct ctdb_node_map *nodemap, *nodemap2;
5862 struct ctdb_req_control request;
5863 uint32_t *pnn_list, *pnn_list2;
5864 int ret, count, count2;
5866 if (argc > 1) {
5867 usage("reloadips");
5870 if (argc == 1) {
5871 nodestring = argv[0];
5874 nodemap = get_nodemap(ctdb, false);
5875 if (nodemap == NULL) {
5876 return 1;
5879 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5880 return 1;
5883 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5884 mem_ctx, &pnn_list);
5885 if (count <= 0) {
5886 fprintf(stderr, "Memory allocation error\n");
5887 return 1;
5890 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5891 mem_ctx, &pnn_list2);
5892 if (count2 <= 0) {
5893 fprintf(stderr, "Memory allocation error\n");
5894 return 1;
5897 /* Disable takeover runs on all connected nodes. A reply
5898 * indicating success is needed from each node so all nodes
5899 * will need to be active.
5901 * A check could be added to not allow reloading of IPs when
5902 * there are disconnected nodes. However, this should
5903 * probably be left up to the administrator.
5905 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5906 pnn_list, count);
5907 if (ret != 0) {
5908 fprintf(stderr, "Failed to disable takeover runs\n");
5909 return ret;
5912 /* Now tell all the desired nodes to reload their public IPs.
5913 * Keep trying this until it succeeds. This assumes all
5914 * failures are transient, which might not be true...
5916 ctdb_req_control_reload_public_ips(&request);
5917 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5918 pnn_list2, count2, TIMEOUT(),
5919 &request, NULL, NULL);
5920 if (ret != 0) {
5921 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5924 /* It isn't strictly necessary to wait until takeover runs are
5925 * re-enabled but doing so can't hurt.
5927 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5928 if (ret != 0) {
5929 fprintf(stderr, "Failed to enable takeover runs\n");
5930 return ret;
5933 return ipreallocate(mem_ctx, ctdb);
5936 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5937 int argc, const char **argv)
5939 ctdb_sock_addr addr;
5940 char *iface;
5942 if (argc != 1) {
5943 usage("ipiface");
5946 if (! parse_ip(argv[0], NULL, 0, &addr)) {
5947 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
5948 return 1;
5951 iface = ctdb_sys_find_ifname(&addr);
5952 if (iface == NULL) {
5953 fprintf(stderr, "Failed to find interface for IP %s\n",
5954 argv[0]);
5955 return 1;
5957 free(iface);
5959 return 0;
5963 static const struct ctdb_cmd {
5964 const char *name;
5965 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5966 bool without_daemon; /* can be run without daemon running ? */
5967 bool remote; /* can be run on remote nodes */
5968 const char *msg;
5969 const char *args;
5970 } ctdb_commands[] = {
5971 { "version", control_version, true, false,
5972 "show version of ctdb", NULL },
5973 { "status", control_status, false, true,
5974 "show node status", NULL },
5975 { "uptime", control_uptime, false, true,
5976 "show node uptime", NULL },
5977 { "ping", control_ping, false, true,
5978 "ping all nodes", NULL },
5979 { "runstate", control_runstate, false, true,
5980 "get/check runstate of a node",
5981 "[setup|first_recovery|startup|running]" },
5982 { "getvar", control_getvar, false, true,
5983 "get a tunable variable", "<name>" },
5984 { "setvar", control_setvar, false, true,
5985 "set a tunable variable", "<name> <value>" },
5986 { "listvars", control_listvars, false, true,
5987 "list tunable variables", NULL },
5988 { "statistics", control_statistics, false, true,
5989 "show ctdb statistics", NULL },
5990 { "statisticsreset", control_statistics_reset, false, true,
5991 "reset ctdb statistics", NULL },
5992 { "stats", control_stats, false, true,
5993 "show rolling statistics", "[count]" },
5994 { "ip", control_ip, false, true,
5995 "show public ips", "[all]" },
5996 { "ipinfo", control_ipinfo, false, true,
5997 "show public ip details", "<ip>" },
5998 { "ifaces", control_ifaces, false, true,
5999 "show interfaces", NULL },
6000 { "setifacelink", control_setifacelink, false, true,
6001 "set interface link status", "<iface> up|down" },
6002 { "process-exists", control_process_exists, false, true,
6003 "check if a process exists on a node", "<pid>" },
6004 { "getdbmap", control_getdbmap, false, true,
6005 "show attached databases", NULL },
6006 { "getdbstatus", control_getdbstatus, false, true,
6007 "show database status", "<dbname|dbid>" },
6008 { "catdb", control_catdb, false, false,
6009 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6010 { "cattdb", control_cattdb, false, false,
6011 "dump local ctdb database", "<dbname|dbid>" },
6012 { "getmonmode", control_getmonmode, false, true,
6013 "show monitoring mode", NULL },
6014 { "getcapabilities", control_getcapabilities, false, true,
6015 "show node capabilities", NULL },
6016 { "pnn", control_pnn, false, false,
6017 "show the pnn of the currnet node", NULL },
6018 { "lvs", control_lvs, false, false,
6019 "show lvs configuration", "master|list|status" },
6020 { "disablemonitor", control_disable_monitor, false, true,
6021 "disable monitoring", NULL },
6022 { "enablemonitor", control_enable_monitor, false, true,
6023 "enable monitoring", NULL },
6024 { "setdebug", control_setdebug, false, true,
6025 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6026 { "getdebug", control_getdebug, false, true,
6027 "get debug level", NULL },
6028 { "attach", control_attach, false, false,
6029 "attach a database", "<dbname> [persistent|replicated]" },
6030 { "detach", control_detach, false, false,
6031 "detach database(s)", "<dbname|dbid> ..." },
6032 { "dumpmemory", control_dumpmemory, false, true,
6033 "dump ctdbd memory map", NULL },
6034 { "rddumpmemory", control_rddumpmemory, false, true,
6035 "dump recoverd memory map", NULL },
6036 { "getpid", control_getpid, false, true,
6037 "get ctdbd process ID", NULL },
6038 { "disable", control_disable, false, true,
6039 "disable a node", NULL },
6040 { "enable", control_enable, false, true,
6041 "enable a node", NULL },
6042 { "stop", control_stop, false, true,
6043 "stop a node", NULL },
6044 { "continue", control_continue, false, true,
6045 "continue a stopped node", NULL },
6046 { "ban", control_ban, false, true,
6047 "ban a node", "<bantime>"},
6048 { "unban", control_unban, false, true,
6049 "unban a node", NULL },
6050 { "shutdown", control_shutdown, false, true,
6051 "shutdown ctdb daemon", NULL },
6052 { "recover", control_recover, false, true,
6053 "force recovery", NULL },
6054 { "sync", control_ipreallocate, false, true,
6055 "run ip reallocation (deprecated)", NULL },
6056 { "ipreallocate", control_ipreallocate, false, true,
6057 "run ip reallocation", NULL },
6058 { "isnotrecmaster", control_isnotrecmaster, false, false,
6059 "check if local node is the recmaster", NULL },
6060 { "gratarp", control_gratarp, false, true,
6061 "send a gratuitous arp", "<ip> <interface>" },
6062 { "tickle", control_tickle, true, false,
6063 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6064 { "gettickles", control_gettickles, false, true,
6065 "get the list of tickles", "<ip> [<port>]" },
6066 { "addtickle", control_addtickle, false, true,
6067 "add a tickle", "<ip>:<port> <ip>:<port>" },
6068 { "deltickle", control_deltickle, false, true,
6069 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6070 { "check_srvids", control_check_srvids, false, true,
6071 "check if srvid is registered", "<id> [<id> ...]" },
6072 { "listnodes", control_listnodes, true, true,
6073 "list nodes in the cluster", NULL },
6074 { "reloadnodes", control_reloadnodes, false, false,
6075 "reload the nodes file all nodes", NULL },
6076 { "moveip", control_moveip, false, false,
6077 "move an ip address to another node", "<ip> <node>" },
6078 { "addip", control_addip, false, true,
6079 "add an ip address to a node", "<ip/mask> <iface>" },
6080 { "delip", control_delip, false, true,
6081 "delete an ip address from a node", "<ip>" },
6082 { "backupdb", control_backupdb, false, false,
6083 "backup a database into a file", "<dbname|dbid> <file>" },
6084 { "restoredb", control_restoredb, false, false,
6085 "restore a database from a file", "<file> [dbname]" },
6086 { "dumpdbbackup", control_dumpdbbackup, true, false,
6087 "dump database from a backup file", "<file>" },
6088 { "wipedb", control_wipedb, false, false,
6089 "wipe the contents of a database.", "<dbname|dbid>"},
6090 { "recmaster", control_recmaster, false, true,
6091 "show the pnn for the recovery master", NULL },
6092 { "event", control_event, true, false,
6093 "event and event script commands", NULL },
6094 { "scriptstatus", control_scriptstatus, true, false,
6095 "show event script status",
6096 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6097 { "natgw", control_natgw, false, false,
6098 "show natgw configuration", "master|list|status" },
6099 { "natgwlist", control_natgwlist, false, false,
6100 "show the nodes belonging to this natgw configuration", NULL },
6101 { "getreclock", control_getreclock, false, true,
6102 "get recovery lock file", NULL },
6103 { "setlmasterrole", control_setlmasterrole, false, true,
6104 "set LMASTER role", "on|off" },
6105 { "setrecmasterrole", control_setrecmasterrole, false, true,
6106 "set RECMASTER role", "on|off"},
6107 { "setdbreadonly", control_setdbreadonly, false, true,
6108 "enable readonly records", "<dbname|dbid>" },
6109 { "setdbsticky", control_setdbsticky, false, true,
6110 "enable sticky records", "<dbname|dbid>"},
6111 { "pfetch", control_pfetch, false, false,
6112 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6113 { "pstore", control_pstore, false, false,
6114 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6115 { "pdelete", control_pdelete, false, false,
6116 "delete record from persistent database", "<dbname|dbid> <key>" },
6117 { "ptrans", control_ptrans, false, false,
6118 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6119 { "tfetch", control_tfetch, false, true,
6120 "fetch a record", "<tdb-file> <key> [<file>]" },
6121 { "tstore", control_tstore, false, true,
6122 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6123 { "readkey", control_readkey, false, false,
6124 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6125 { "writekey", control_writekey, false, false,
6126 "write value for a database key", "<dbname|dbid> <key> <value>" },
6127 { "deletekey", control_deletekey, false, false,
6128 "delete a database key", "<dbname|dbid> <key>" },
6129 { "checktcpport", control_checktcpport, true, false,
6130 "check if a service is bound to a specific tcp port or not", "<port>" },
6131 { "getdbseqnum", control_getdbseqnum, false, false,
6132 "get database sequence number", "<dbname|dbid>" },
6133 { "nodestatus", control_nodestatus, false, true,
6134 "show and return node status", "[all|<pnn-list>]" },
6135 { "dbstatistics", control_dbstatistics, false, true,
6136 "show database statistics", "<dbname|dbid>" },
6137 { "reloadips", control_reloadips, false, false,
6138 "reload the public addresses file", "[all|<pnn-list>]" },
6139 { "ipiface", control_ipiface, true, false,
6140 "Find the interface an ip address is hosted on", "<ip>" },
6143 static const struct ctdb_cmd *match_command(const char *command)
6145 const struct ctdb_cmd *cmd;
6146 int i;
6148 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6149 cmd = &ctdb_commands[i];
6150 if (strlen(command) == strlen(cmd->name) &&
6151 strncmp(command, cmd->name, strlen(command)) == 0) {
6152 return cmd;
6156 return NULL;
6161 * Show usage message
6163 static void usage_full(void)
6165 int i;
6167 poptPrintHelp(pc, stdout, 0);
6168 printf("\nCommands:\n");
6169 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6170 printf(" %-15s %-27s %s\n",
6171 ctdb_commands[i].name,
6172 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6173 ctdb_commands[i].msg);
6177 static void usage(const char *command)
6179 const struct ctdb_cmd *cmd;
6181 if (command == NULL) {
6182 usage_full();
6183 exit(1);
6186 cmd = match_command(command);
6187 if (cmd == NULL) {
6188 usage_full();
6189 } else {
6190 poptPrintUsage(pc, stdout, 0);
6191 printf("\nCommands:\n");
6192 printf(" %-15s %-27s %s\n",
6193 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6196 exit(1);
6199 struct poptOption cmdline_options[] = {
6200 POPT_AUTOHELP
6201 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6202 "CTDB socket path", "filename" },
6203 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6204 "debug level"},
6205 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6206 "timelimit (in seconds)" },
6207 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6208 "node specification - integer" },
6209 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6210 "enable machine readable output", NULL },
6211 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6212 "specify separator for machine readable output", "CHAR" },
6213 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6214 "enable machine parsable output with separator |", NULL },
6215 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6216 "enable verbose output", NULL },
6217 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6218 "die if runtime exceeds this limit (in seconds)" },
6219 POPT_TABLEEND
6222 static int process_command(const struct ctdb_cmd *cmd, int argc,
6223 const char **argv)
6225 TALLOC_CTX *tmp_ctx;
6226 struct ctdb_context *ctdb;
6227 int ret;
6228 bool status;
6229 uint64_t srvid_offset;
6231 tmp_ctx = talloc_new(NULL);
6232 if (tmp_ctx == NULL) {
6233 fprintf(stderr, "Memory allocation error\n");
6234 goto fail;
6237 if (cmd->without_daemon) {
6238 if (options.pnn != -1) {
6239 fprintf(stderr,
6240 "Cannot specify node for command %s\n",
6241 cmd->name);
6242 goto fail;
6245 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6246 talloc_free(tmp_ctx);
6247 return ret;
6250 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6251 if (ctdb == NULL) {
6252 fprintf(stderr, "Memory allocation error\n");
6253 goto fail;
6256 ctdb->ev = tevent_context_init(ctdb);
6257 if (ctdb->ev == NULL) {
6258 fprintf(stderr, "Failed to initialize tevent\n");
6259 goto fail;
6262 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6263 if (ret != 0) {
6264 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6265 options.socket);
6267 if (!find_node_xpnn(ctdb, NULL)) {
6268 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6270 goto fail;
6273 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6274 srvid_offset = getpid() & 0xFFFF;
6275 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6277 if (options.pnn != -1) {
6278 status = verify_pnn(ctdb, options.pnn);
6279 if (! status) {
6280 goto fail;
6283 ctdb->cmd_pnn = options.pnn;
6284 } else {
6285 ctdb->cmd_pnn = ctdb->pnn;
6288 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6289 fprintf(stderr, "Node cannot be specified for command %s\n",
6290 cmd->name);
6291 goto fail;
6294 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6295 talloc_free(tmp_ctx);
6296 return ret;
6298 fail:
6299 talloc_free(tmp_ctx);
6300 return 1;
6303 static void signal_handler(int sig)
6305 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6308 static void alarm_handler(int sig)
6310 /* Kill any child processes */
6311 signal(SIGTERM, signal_handler);
6312 kill(0, SIGTERM);
6314 _exit(1);
6317 int main(int argc, const char *argv[])
6319 int opt;
6320 const char **extra_argv;
6321 int extra_argc;
6322 const struct ctdb_cmd *cmd;
6323 const char *ctdb_socket;
6324 int loglevel;
6325 int ret;
6327 setlinebuf(stdout);
6329 /* Set default options */
6330 options.socket = CTDB_SOCKET;
6331 options.debuglevelstr = NULL;
6332 options.timelimit = 10;
6333 options.sep = "|";
6334 options.maxruntime = 0;
6335 options.pnn = -1;
6337 ctdb_socket = getenv("CTDB_SOCKET");
6338 if (ctdb_socket != NULL) {
6339 options.socket = ctdb_socket;
6342 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6343 POPT_CONTEXT_KEEP_FIRST);
6344 while ((opt = poptGetNextOpt(pc)) != -1) {
6345 fprintf(stderr, "Invalid option %s: %s\n",
6346 poptBadOption(pc, 0), poptStrerror(opt));
6347 exit(1);
6350 if (options.maxruntime == 0) {
6351 const char *ctdb_timeout;
6353 ctdb_timeout = getenv("CTDB_TIMEOUT");
6354 if (ctdb_timeout != NULL) {
6355 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6356 } else {
6357 options.maxruntime = 120;
6360 if (options.maxruntime <= 120) {
6361 /* default timeout is 120 seconds */
6362 options.maxruntime = 120;
6365 if (options.machineparsable) {
6366 options.machinereadable = 1;
6369 /* setup the remaining options for the commands */
6370 extra_argc = 0;
6371 extra_argv = poptGetArgs(pc);
6372 if (extra_argv) {
6373 extra_argv++;
6374 while (extra_argv[extra_argc]) extra_argc++;
6377 if (extra_argc < 1) {
6378 usage(NULL);
6381 cmd = match_command(extra_argv[0]);
6382 if (cmd == NULL) {
6383 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6384 exit(1);
6387 /* Enable logging */
6388 setup_logging("ctdb", DEBUG_STDERR);
6389 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6390 DEBUGLEVEL = loglevel;
6391 } else {
6392 DEBUGLEVEL = DEBUG_ERR;
6395 signal(SIGALRM, alarm_handler);
6396 alarm(options.maxruntime);
6398 ret = process_command(cmd, extra_argc, extra_argv);
6399 if (ret == -1) {
6400 ret = 1;
6403 (void)poptFreeContext(pc);
6405 return ret;