s3:smbd: rename has_ctdb_public_ip to has_cluster_movable_ip
[Samba.git] / ctdb / tools / ctdb.c
blobe21d2d4b562c6ac96d317e562e274a8444ac2054
1 /*
2 CTDB control tool
4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "replace.h"
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
27 #include <ctype.h>
28 #include <popt.h>
29 #include <talloc.h>
30 #include <tevent.h>
31 #include <tdb.h>
33 #include "version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
37 #include "lib/util/smb_strtox.h"
39 #include "common/db_hash.h"
40 #include "common/logging.h"
41 #include "common/path.h"
42 #include "protocol/protocol.h"
43 #include "protocol/protocol_api.h"
44 #include "protocol/protocol_util.h"
45 #include "common/system_socket.h"
46 #include "client/client.h"
47 #include "client/client_sync.h"
49 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
51 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
52 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
54 static struct {
55 const char *debuglevelstr;
56 int timelimit;
57 int pnn;
58 int machinereadable;
59 const char *sep;
60 int machineparsable;
61 int verbose;
62 int maxruntime;
63 int printemptyrecords;
64 int printdatasize;
65 int printlmaster;
66 int printhash;
67 int printrecordflags;
68 } options;
70 static poptContext pc;
72 struct ctdb_context {
73 struct tevent_context *ev;
74 struct ctdb_client_context *client;
75 struct ctdb_node_map *nodemap;
76 uint32_t pnn, cmd_pnn;
77 uint64_t srvid;
80 static void usage(const char *command);
83 * Utility Functions
86 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
88 return (tv2->tv_sec - tv->tv_sec) +
89 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
92 static struct ctdb_node_and_flags *get_node_by_pnn(
93 struct ctdb_node_map *nodemap,
94 uint32_t pnn)
96 unsigned int i;
98 for (i=0; i<nodemap->num; i++) {
99 if (nodemap->node[i].pnn == pnn) {
100 return &nodemap->node[i];
103 return NULL;
106 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
108 static const struct {
109 uint32_t flag;
110 const char *name;
111 } flag_names[] = {
112 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
113 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
114 { NODE_FLAGS_BANNED, "BANNED" },
115 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
116 { NODE_FLAGS_DELETED, "DELETED" },
117 { NODE_FLAGS_STOPPED, "STOPPED" },
118 { NODE_FLAGS_INACTIVE, "INACTIVE" },
120 char *flags_str = NULL;
121 size_t i;
123 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
124 if (flags & flag_names[i].flag) {
125 if (flags_str == NULL) {
126 flags_str = talloc_asprintf(mem_ctx,
127 "%s", flag_names[i].name);
128 } else {
129 flags_str = talloc_asprintf_append(flags_str,
130 "|%s", flag_names[i].name);
132 if (flags_str == NULL) {
133 return "OUT-OF-MEMORY";
137 if (flags_str == NULL) {
138 return "OK";
141 return flags_str;
144 static uint64_t next_srvid(struct ctdb_context *ctdb)
146 ctdb->srvid += 1;
147 return ctdb->srvid;
151 * Get consistent nodemap information.
153 * If nodemap is already cached, use that. If not get it.
154 * If the current node is BANNED, then get nodemap from "better" node.
156 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
158 TALLOC_CTX *tmp_ctx;
159 struct ctdb_node_map *nodemap;
160 struct ctdb_node_and_flags *node;
161 uint32_t current_node;
162 int ret;
164 if (force) {
165 TALLOC_FREE(ctdb->nodemap);
168 if (ctdb->nodemap != NULL) {
169 return ctdb->nodemap;
172 tmp_ctx = talloc_new(ctdb);
173 if (tmp_ctx == NULL) {
174 return false;
177 current_node = ctdb->pnn;
178 again:
179 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
180 current_node, TIMEOUT(), &nodemap);
181 if (ret != 0) {
182 fprintf(stderr, "Failed to get nodemap from node %u\n",
183 current_node);
184 goto failed;
187 node = get_node_by_pnn(nodemap, current_node);
188 if (node->flags & NODE_FLAGS_BANNED) {
189 /* Pick next node */
190 do {
191 current_node = (current_node + 1) % nodemap->num;
192 node = get_node_by_pnn(nodemap, current_node);
193 if (! (node->flags &
194 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
195 break;
197 } while (current_node != ctdb->pnn);
199 if (current_node == ctdb->pnn) {
200 /* Tried all nodes in the cluster */
201 fprintf(stderr, "Warning: All nodes are banned.\n");
202 goto failed;
205 goto again;
208 ctdb->nodemap = talloc_steal(ctdb, nodemap);
209 return nodemap;
211 failed:
212 talloc_free(tmp_ctx);
213 return NULL;
216 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
218 struct ctdb_node_map *nodemap;
219 bool found;
220 unsigned int i;
222 if (pnn == -1) {
223 return false;
226 nodemap = get_nodemap(ctdb, false);
227 if (nodemap == NULL) {
228 return false;
231 found = false;
232 for (i=0; i<nodemap->num; i++) {
233 if (nodemap->node[i].pnn == (uint32_t)pnn) {
234 found = true;
235 break;
238 if (! found) {
239 fprintf(stderr, "Node %u does not exist\n", pnn);
240 return false;
243 if (nodemap->node[i].flags &
244 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
245 fprintf(stderr, "Node %u has status %s\n", pnn,
246 pretty_print_flags(ctdb, nodemap->node[i].flags));
247 return false;
250 return true;
253 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
254 struct ctdb_node_map *nodemap)
256 struct ctdb_node_map *nodemap2;
258 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
259 if (nodemap2 == NULL) {
260 return NULL;
263 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
264 nodemap->num);
265 if (nodemap2->node == NULL) {
266 talloc_free(nodemap2);
267 return NULL;
270 return nodemap2;
274 * Get the number and the list of matching nodes
276 * nodestring := NULL | all | pnn,[pnn,...]
278 * If nodestring is NULL, use the current node.
280 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
281 const char *nodestring,
282 struct ctdb_node_map **out)
284 struct ctdb_node_map *nodemap, *nodemap2;
285 struct ctdb_node_and_flags *node;
286 unsigned int i;
288 nodemap = get_nodemap(ctdb, false);
289 if (nodemap == NULL) {
290 return false;
293 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
294 if (nodemap2 == NULL) {
295 return false;
298 if (nodestring == NULL) {
299 for (i=0; i<nodemap->num; i++) {
300 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
301 nodemap2->node[0] = nodemap->node[i];
302 break;
305 nodemap2->num = 1;
307 goto done;
310 if (strcmp(nodestring, "all") == 0) {
311 for (i=0; i<nodemap->num; i++) {
312 nodemap2->node[i] = nodemap->node[i];
314 nodemap2->num = nodemap->num;
316 goto done;
317 } else {
318 char *ns, *tok;
319 int error = 0;
321 ns = talloc_strdup(mem_ctx, nodestring);
322 if (ns == NULL) {
323 return false;
326 tok = strtok(ns, ",");
327 while (tok != NULL) {
328 uint32_t pnn;
330 pnn = (uint32_t)smb_strtoul(tok,
331 NULL,
333 &error,
334 SMB_STR_STANDARD);
335 if (error != 0) {
336 fprintf(stderr, "Invalid node %s\n", tok);
337 return false;
340 node = get_node_by_pnn(nodemap, pnn);
341 if (node == NULL) {
342 fprintf(stderr, "Node %u does not exist\n",
343 pnn);
344 return false;
347 nodemap2->node[nodemap2->num] = *node;
348 nodemap2->num += 1;
350 tok = strtok(NULL, ",");
354 done:
355 *out = nodemap2;
356 return true;
359 /* Compare IP address */
360 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
362 bool ret = false;
364 if (ip1->sa.sa_family != ip2->sa.sa_family) {
365 return false;
368 switch (ip1->sa.sa_family) {
369 case AF_INET:
370 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
371 sizeof(struct in_addr)) == 0);
372 break;
374 case AF_INET6:
375 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
376 sizeof(struct in6_addr)) == 0);
377 break;
380 return ret;
383 /* Append a node to a node map with given address and flags */
384 static bool node_map_add(struct ctdb_node_map *nodemap,
385 const char *nstr, uint32_t flags)
387 ctdb_sock_addr addr;
388 uint32_t num;
389 struct ctdb_node_and_flags *n;
390 int ret;
392 ret = ctdb_sock_addr_from_string(nstr, &addr, false);
393 if (ret != 0) {
394 fprintf(stderr, "Invalid IP address %s\n", nstr);
395 return false;
398 num = nodemap->num;
399 nodemap->node = talloc_realloc(nodemap, nodemap->node,
400 struct ctdb_node_and_flags, num+1);
401 if (nodemap->node == NULL) {
402 return false;
405 n = &nodemap->node[num];
406 n->addr = addr;
407 n->pnn = num;
408 n->flags = flags;
410 nodemap->num = num+1;
411 return true;
414 /* Read a nodes file into a node map */
415 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
416 const char *nlist)
418 char **lines;
419 int nlines;
420 int i;
421 struct ctdb_node_map *nodemap;
423 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
424 if (nodemap == NULL) {
425 return NULL;
428 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
429 if (lines == NULL) {
430 return NULL;
433 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
434 nlines--;
437 for (i=0; i<nlines; i++) {
438 char *node;
439 uint32_t flags;
440 size_t len;
442 node = lines[i];
443 /* strip leading spaces */
444 while((*node == ' ') || (*node == '\t')) {
445 node++;
448 len = strlen(node);
450 /* strip trailing spaces */
451 while ((len > 1) &&
452 ((node[len-1] == ' ') || (node[len-1] == '\t')))
454 node[len-1] = '\0';
455 len--;
458 if (len == 0) {
459 continue;
461 if (*node == '#') {
462 /* A "deleted" node is a node that is
463 commented out in the nodes file. This is
464 used instead of removing a line, which
465 would cause subsequent nodes to change
466 their PNN. */
467 flags = NODE_FLAGS_DELETED;
468 node = discard_const("0.0.0.0");
469 } else {
470 flags = 0;
472 if (! node_map_add(nodemap, node, flags)) {
473 talloc_free(lines);
474 TALLOC_FREE(nodemap);
475 return NULL;
479 talloc_free(lines);
480 return nodemap;
483 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
485 struct ctdb_node_map *nodemap;
486 const char *nodes_list = NULL;
488 const char *basedir = getenv("CTDB_BASE");
489 if (basedir == NULL) {
490 basedir = CTDB_ETCDIR;
492 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
493 if (nodes_list == NULL) {
494 fprintf(stderr, "Memory allocation error\n");
495 return NULL;
498 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
499 if (nodemap == NULL) {
500 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
501 nodes_list);
502 return NULL;
505 return nodemap;
508 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
509 struct ctdb_context *ctdb,
510 struct ctdb_dbid_map *dbmap,
511 const char *db_name)
513 struct ctdb_dbid *db = NULL;
514 const char *name;
515 unsigned int i;
516 int ret;
518 for (i=0; i<dbmap->num; i++) {
519 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
520 ctdb->pnn, TIMEOUT(),
521 dbmap->dbs[i].db_id, &name);
522 if (ret != 0) {
523 return false;
526 if (strcmp(db_name, name) == 0) {
527 talloc_free(discard_const(name));
528 db = &dbmap->dbs[i];
529 break;
533 return db;
536 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
537 const char *db_arg, uint32_t *db_id,
538 const char **db_name, uint8_t *db_flags)
540 struct ctdb_dbid_map *dbmap;
541 struct ctdb_dbid *db = NULL;
542 uint32_t id = 0;
543 const char *name = NULL;
544 unsigned int i;
545 int ret = 0;
547 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
548 ctdb->pnn, TIMEOUT(), &dbmap);
549 if (ret != 0) {
550 return false;
553 if (strncmp(db_arg, "0x", 2) == 0) {
554 id = smb_strtoul(db_arg, NULL, 0, &ret, SMB_STR_STANDARD);
555 if (ret != 0) {
556 return false;
558 for (i=0; i<dbmap->num; i++) {
559 if (id == dbmap->dbs[i].db_id) {
560 db = &dbmap->dbs[i];
561 break;
564 } else {
565 name = db_arg;
566 db = db_find(mem_ctx, ctdb, dbmap, name);
569 if (db == NULL) {
570 fprintf(stderr, "No database matching '%s' found\n", db_arg);
571 return false;
574 if (name == NULL) {
575 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
576 ctdb->pnn, TIMEOUT(), id, &name);
577 if (ret != 0) {
578 return false;
582 if (db_id != NULL) {
583 *db_id = db->db_id;
585 if (db_name != NULL) {
586 *db_name = talloc_strdup(mem_ctx, name);
588 if (db_flags != NULL) {
589 *db_flags = db->flags;
591 return true;
594 static int h2i(char h)
596 if (h >= 'a' && h <= 'f') {
597 return h - 'a' + 10;
599 if (h >= 'A' && h <= 'F') {
600 return h - 'A' + 10;
602 return h - '0';
605 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
606 TDB_DATA *out)
608 unsigned int i;
609 TDB_DATA data;
611 if (len & 0x01) {
612 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
613 str);
614 return EINVAL;
617 data.dsize = len / 2;
618 data.dptr = talloc_size(mem_ctx, data.dsize);
619 if (data.dptr == NULL) {
620 return ENOMEM;
623 for (i=0; i<data.dsize; i++) {
624 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
627 *out = data;
628 return 0;
631 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
632 TDB_DATA *out)
634 TDB_DATA data;
635 int ret = 0;
637 if (strncmp(str, "0x", 2) == 0) {
638 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
639 if (ret != 0) {
640 return ret;
642 } else {
643 data.dptr = talloc_memdup(mem_ctx, str, len);
644 if (data.dptr == NULL) {
645 return ENOMEM;
647 data.dsize = len;
650 *out = data;
651 return 0;
654 static int run_helper(TALLOC_CTX *mem_ctx, const char *command,
655 const char *path, int argc, const char **argv)
657 pid_t pid;
658 int save_errno, status, ret;
659 const char **new_argv;
660 int i;
662 new_argv = talloc_array(mem_ctx, const char *, argc + 2);
663 if (new_argv == NULL) {
664 return ENOMEM;
667 new_argv[0] = path;
668 for (i=0; i<argc; i++) {
669 new_argv[i+1] = argv[i];
671 new_argv[argc+1] = NULL;
673 pid = fork();
674 if (pid < 0) {
675 save_errno = errno;
676 talloc_free(new_argv);
677 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
678 command, path, strerror(save_errno));
679 return save_errno;
682 if (pid == 0) {
683 ret = execv(path, discard_const(new_argv));
684 if (ret == -1) {
685 _exit(64+errno);
687 /* Should not happen */
688 _exit(64+ENOEXEC);
691 talloc_free(new_argv);
693 ret = waitpid(pid, &status, 0);
694 if (ret == -1) {
695 save_errno = errno;
696 fprintf(stderr, "waitpid() failed for %s - %s\n",
697 command, strerror(save_errno));
698 return save_errno;
701 if (WIFEXITED(status)) {
702 int pstatus = WEXITSTATUS(status);
703 if (WIFSIGNALED(status)) {
704 fprintf(stderr, "%s terminated with signal %d\n",
705 command, WTERMSIG(status));
706 ret = EINTR;
707 } else if (pstatus >= 64 && pstatus < 255) {
708 fprintf(stderr, "%s failed with error %d\n",
709 command, pstatus-64);
710 ret = pstatus - 64;
711 } else {
712 ret = pstatus;
714 return ret;
715 } else if (WIFSIGNALED(status)) {
716 fprintf(stderr, "%s terminated with signal %d\n",
717 command, WTERMSIG(status));
718 return EINTR;
721 return 0;
725 * Command Functions
728 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
729 int argc, const char **argv)
731 printf("%s\n", SAMBA_VERSION_STRING);
732 return 0;
735 static bool partially_online(TALLOC_CTX *mem_ctx,
736 struct ctdb_context *ctdb,
737 struct ctdb_node_and_flags *node)
739 struct ctdb_iface_list *iface_list;
740 unsigned int i;
741 int ret;
742 bool status = false;
744 if (node->flags != 0) {
745 return false;
748 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
749 node->pnn, TIMEOUT(), &iface_list);
750 if (ret != 0) {
751 return false;
754 status = false;
755 for (i=0; i < iface_list->num; i++) {
756 if (iface_list->iface[i].link_state == 0) {
757 status = true;
758 break;
762 return status;
765 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
766 struct ctdb_context *ctdb,
767 struct ctdb_node_map *nodemap,
768 uint32_t mypnn)
770 struct ctdb_node_and_flags *node;
771 unsigned int i;
773 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
774 options.sep,
775 "Node", options.sep,
776 "IP", options.sep,
777 "Disconnected", options.sep,
778 "Banned", options.sep,
779 "Disabled", options.sep,
780 "Unhealthy", options.sep,
781 "Stopped", options.sep,
782 "Inactive", options.sep,
783 "PartiallyOnline", options.sep,
784 "ThisNode", options.sep);
786 for (i=0; i<nodemap->num; i++) {
787 node = &nodemap->node[i];
788 if (node->flags & NODE_FLAGS_DELETED) {
789 continue;
792 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
793 options.sep,
794 node->pnn, options.sep,
795 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
796 options.sep,
797 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
798 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
799 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
800 options.sep,
801 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
802 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
803 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
804 partially_online(mem_ctx, ctdb, node), options.sep,
805 (node->pnn == mypnn)?'Y':'N', options.sep);
810 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
811 struct ctdb_node_map *nodemap, uint32_t mypnn,
812 bool print_header)
814 struct ctdb_node_and_flags *node;
815 int num_deleted_nodes = 0;
816 unsigned int i;
818 for (i=0; i<nodemap->num; i++) {
819 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
820 num_deleted_nodes++;
824 if (print_header) {
825 if (num_deleted_nodes == 0) {
826 printf("Number of nodes:%d\n", nodemap->num);
827 } else {
828 printf("Number of nodes:%d "
829 "(including %d deleted nodes)\n",
830 nodemap->num, num_deleted_nodes);
834 for (i=0; i<nodemap->num; i++) {
835 node = &nodemap->node[i];
836 if (node->flags & NODE_FLAGS_DELETED) {
837 continue;
840 printf("pnn:%u %-16s %s%s\n",
841 node->pnn,
842 ctdb_sock_addr_to_string(mem_ctx, &node->addr, false),
843 partially_online(mem_ctx, ctdb, node) ?
844 "PARTIALLYONLINE" :
845 pretty_print_flags(mem_ctx, node->flags),
846 node->pnn == mypnn ? " (THIS NODE)" : "");
850 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
851 struct ctdb_node_map *nodemap, uint32_t mypnn,
852 struct ctdb_vnn_map *vnnmap, int recmode,
853 uint32_t recmaster)
855 unsigned int i;
857 print_nodemap(mem_ctx, ctdb, nodemap, mypnn, true);
859 if (vnnmap->generation == INVALID_GENERATION) {
860 printf("Generation:INVALID\n");
861 } else {
862 printf("Generation:%u\n", vnnmap->generation);
864 printf("Size:%d\n", vnnmap->size);
865 for (i=0; i<vnnmap->size; i++) {
866 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
869 printf("Recovery mode:%s (%d)\n",
870 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
871 recmode);
872 printf("Recovery master:%d\n", recmaster);
875 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
876 int argc, const char **argv)
878 struct ctdb_node_map *nodemap;
879 struct ctdb_vnn_map *vnnmap;
880 int recmode;
881 uint32_t recmaster;
882 int ret;
884 if (argc != 0) {
885 usage("status");
888 nodemap = get_nodemap(ctdb, false);
889 if (nodemap == NULL) {
890 return 1;
893 if (options.machinereadable == 1) {
894 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
895 return 0;
898 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
899 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
900 if (ret != 0) {
901 return ret;
904 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
905 ctdb->cmd_pnn, TIMEOUT(), &recmode);
906 if (ret != 0) {
907 return ret;
910 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
911 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
912 if (ret != 0) {
913 return ret;
916 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
917 recmode, recmaster);
918 return 0;
921 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
922 int argc, const char **argv)
924 struct ctdb_uptime *uptime;
925 int ret, tmp, days, hours, minutes, seconds;
927 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
928 ctdb->cmd_pnn, TIMEOUT(), &uptime);
929 if (ret != 0) {
930 return ret;
933 printf("Current time of node %-4u : %s",
934 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
936 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
937 seconds = tmp % 60; tmp /= 60;
938 minutes = tmp % 60; tmp /= 60;
939 hours = tmp % 24; tmp /= 24;
940 days = tmp;
942 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
943 days, hours, minutes, seconds,
944 ctime(&uptime->ctdbd_start_time.tv_sec));
946 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
947 seconds = tmp % 60; tmp /= 60;
948 minutes = tmp % 60; tmp /= 60;
949 hours = tmp % 24; tmp /= 24;
950 days = tmp;
952 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
953 days, hours, minutes, seconds,
954 ctime(&uptime->last_recovery_finished.tv_sec));
956 printf("Duration of last recovery/failover: %lf seconds\n",
957 timeval_delta(&uptime->last_recovery_finished,
958 &uptime->last_recovery_started));
960 return 0;
963 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
964 int argc, const char **argv)
966 struct timeval tv;
967 int ret, num_clients;
969 tv = timeval_current();
970 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
971 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
972 if (ret != 0) {
973 return ret;
976 printf("response from %u time=%.6f sec (%d clients)\n",
977 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
978 return 0;
981 const char *runstate_to_string(enum ctdb_runstate runstate);
982 enum ctdb_runstate runstate_from_string(const char *runstate_str);
984 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
985 int argc, const char **argv)
987 enum ctdb_runstate runstate;
988 bool found;
989 int ret, i;
991 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
992 ctdb->cmd_pnn, TIMEOUT(), &runstate);
993 if (ret != 0) {
994 return ret;
997 found = true;
998 for (i=0; i<argc; i++) {
999 enum ctdb_runstate t;
1001 found = false;
1002 t = ctdb_runstate_from_string(argv[i]);
1003 if (t == CTDB_RUNSTATE_UNKNOWN) {
1004 printf("Invalid run state (%s)\n", argv[i]);
1005 return 1;
1008 if (t == runstate) {
1009 found = true;
1010 break;
1014 if (! found) {
1015 printf("CTDB not in required run state (got %s)\n",
1016 ctdb_runstate_to_string(runstate));
1017 return 1;
1020 printf("%s\n", ctdb_runstate_to_string(runstate));
1021 return 0;
1024 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1025 int argc, const char **argv)
1027 struct ctdb_var_list *tun_var_list;
1028 uint32_t value;
1029 int ret, i;
1030 bool found;
1032 if (argc != 1) {
1033 usage("getvar");
1036 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1037 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1038 if (ret != 0) {
1039 fprintf(stderr,
1040 "Failed to get list of variables from node %u\n",
1041 ctdb->cmd_pnn);
1042 return ret;
1045 found = false;
1046 for (i=0; i<tun_var_list->count; i++) {
1047 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1048 found = true;
1049 break;
1053 if (! found) {
1054 printf("No such tunable %s\n", argv[0]);
1055 return 1;
1058 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1059 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1060 if (ret != 0) {
1061 return ret;
1064 printf("%-26s = %u\n", argv[0], value);
1065 return 0;
1068 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1069 int argc, const char **argv)
1071 struct ctdb_var_list *tun_var_list;
1072 struct ctdb_tunable tunable;
1073 bool found;
1074 int i;
1075 int ret = 0;
1077 if (argc != 2) {
1078 usage("setvar");
1081 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1082 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1083 if (ret != 0) {
1084 fprintf(stderr,
1085 "Failed to get list of variables from node %u\n",
1086 ctdb->cmd_pnn);
1087 return ret;
1090 found = false;
1091 for (i=0; i<tun_var_list->count; i++) {
1092 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1093 found = true;
1094 break;
1098 if (! found) {
1099 printf("No such tunable %s\n", argv[0]);
1100 return 1;
1103 tunable.name = argv[0];
1104 tunable.value = smb_strtoul(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
1105 if (ret != 0) {
1106 return ret;
1109 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1110 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1111 if (ret != 0) {
1112 if (ret == 1) {
1113 fprintf(stderr,
1114 "Setting obsolete tunable variable '%s'\n",
1115 tunable.name);
1116 return 0;
1120 return ret;
1123 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1124 int argc, const char **argv)
1126 struct ctdb_var_list *tun_var_list;
1127 int ret, i;
1129 if (argc != 0) {
1130 usage("listvars");
1133 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1134 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1135 if (ret != 0) {
1136 return ret;
1139 for (i=0; i<tun_var_list->count; i++) {
1140 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1143 return 0;
1146 const struct {
1147 const char *name;
1148 uint32_t offset;
1149 } stats_fields[] = {
1150 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1151 STATISTICS_FIELD(num_clients),
1152 STATISTICS_FIELD(frozen),
1153 STATISTICS_FIELD(recovering),
1154 STATISTICS_FIELD(num_recoveries),
1155 STATISTICS_FIELD(client_packets_sent),
1156 STATISTICS_FIELD(client_packets_recv),
1157 STATISTICS_FIELD(node_packets_sent),
1158 STATISTICS_FIELD(node_packets_recv),
1159 STATISTICS_FIELD(keepalive_packets_sent),
1160 STATISTICS_FIELD(keepalive_packets_recv),
1161 STATISTICS_FIELD(node.req_call),
1162 STATISTICS_FIELD(node.reply_call),
1163 STATISTICS_FIELD(node.req_dmaster),
1164 STATISTICS_FIELD(node.reply_dmaster),
1165 STATISTICS_FIELD(node.reply_error),
1166 STATISTICS_FIELD(node.req_message),
1167 STATISTICS_FIELD(node.req_control),
1168 STATISTICS_FIELD(node.reply_control),
1169 STATISTICS_FIELD(node.req_tunnel),
1170 STATISTICS_FIELD(client.req_call),
1171 STATISTICS_FIELD(client.req_message),
1172 STATISTICS_FIELD(client.req_control),
1173 STATISTICS_FIELD(client.req_tunnel),
1174 STATISTICS_FIELD(timeouts.call),
1175 STATISTICS_FIELD(timeouts.control),
1176 STATISTICS_FIELD(timeouts.traverse),
1177 STATISTICS_FIELD(locks.num_calls),
1178 STATISTICS_FIELD(locks.num_current),
1179 STATISTICS_FIELD(locks.num_pending),
1180 STATISTICS_FIELD(locks.num_failed),
1181 STATISTICS_FIELD(total_calls),
1182 STATISTICS_FIELD(pending_calls),
1183 STATISTICS_FIELD(childwrite_calls),
1184 STATISTICS_FIELD(pending_childwrite_calls),
1185 STATISTICS_FIELD(memory_used),
1186 STATISTICS_FIELD(max_hop_count),
1187 STATISTICS_FIELD(total_ro_delegations),
1188 STATISTICS_FIELD(total_ro_revokes),
1191 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1193 static void print_statistics_machine(struct ctdb_statistics *s,
1194 bool show_header)
1196 size_t i;
1198 if (show_header) {
1199 printf("CTDB version%s", options.sep);
1200 printf("Current time of statistics%s", options.sep);
1201 printf("Statistics collected since%s", options.sep);
1202 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1203 printf("%s%s", stats_fields[i].name, options.sep);
1205 printf("num_reclock_ctdbd_latency%s", options.sep);
1206 printf("min_reclock_ctdbd_latency%s", options.sep);
1207 printf("avg_reclock_ctdbd_latency%s", options.sep);
1208 printf("max_reclock_ctdbd_latency%s", options.sep);
1210 printf("num_reclock_recd_latency%s", options.sep);
1211 printf("min_reclock_recd_latency%s", options.sep);
1212 printf("avg_reclock_recd_latency%s", options.sep);
1213 printf("max_reclock_recd_latency%s", options.sep);
1215 printf("num_call_latency%s", options.sep);
1216 printf("min_call_latency%s", options.sep);
1217 printf("avg_call_latency%s", options.sep);
1218 printf("max_call_latency%s", options.sep);
1220 printf("num_lockwait_latency%s", options.sep);
1221 printf("min_lockwait_latency%s", options.sep);
1222 printf("avg_lockwait_latency%s", options.sep);
1223 printf("max_lockwait_latency%s", options.sep);
1225 printf("num_childwrite_latency%s", options.sep);
1226 printf("min_childwrite_latency%s", options.sep);
1227 printf("avg_childwrite_latency%s", options.sep);
1228 printf("max_childwrite_latency%s", options.sep);
1229 printf("\n");
1232 printf("%u%s", CTDB_PROTOCOL, options.sep);
1233 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1234 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1235 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1236 printf("%u%s",
1237 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1238 options.sep);
1240 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1241 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1242 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1243 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1245 printf("%u%s", s->reclock.recd.num, options.sep);
1246 printf("%.6f%s", s->reclock.recd.min, options.sep);
1247 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1248 printf("%.6f%s", s->reclock.recd.max, options.sep);
1250 printf("%d%s", s->call_latency.num, options.sep);
1251 printf("%.6f%s", s->call_latency.min, options.sep);
1252 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1253 printf("%.6f%s", s->call_latency.max, options.sep);
1255 printf("%u%s", s->locks.latency.num, options.sep);
1256 printf("%.6f%s", s->locks.latency.min, options.sep);
1257 printf("%.6f%s", LATENCY_AVG(s->locks.latency), options.sep);
1258 printf("%.6f%s", s->locks.latency.max, options.sep);
1260 printf("%d%s", s->childwrite_latency.num, options.sep);
1261 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1262 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1263 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1264 printf("\n");
1267 static void print_statistics(struct ctdb_statistics *s)
1269 int tmp, days, hours, minutes, seconds;
1270 size_t i;
1271 const char *prefix = NULL;
1272 int preflen = 0;
1274 tmp = s->statistics_current_time.tv_sec -
1275 s->statistics_start_time.tv_sec;
1276 seconds = tmp % 60; tmp /= 60;
1277 minutes = tmp % 60; tmp /= 60;
1278 hours = tmp % 24; tmp /= 24;
1279 days = tmp;
1281 printf("CTDB version %u\n", CTDB_PROTOCOL);
1282 printf("Current time of statistics : %s",
1283 ctime(&s->statistics_current_time.tv_sec));
1284 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1285 days, hours, minutes, seconds,
1286 ctime(&s->statistics_start_time.tv_sec));
1288 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1289 if (strchr(stats_fields[i].name, '.') != NULL) {
1290 preflen = strcspn(stats_fields[i].name, ".") + 1;
1291 if (! prefix ||
1292 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1293 prefix = stats_fields[i].name;
1294 printf(" %*.*s\n", preflen-1, preflen-1,
1295 stats_fields[i].name);
1297 } else {
1298 preflen = 0;
1300 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1301 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1302 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1305 printf(" hop_count_buckets:");
1306 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1307 printf(" %d", s->hop_count_bucket[i]);
1309 printf("\n");
1310 printf(" lock_buckets:");
1311 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1312 printf(" %d", s->locks.buckets[i]);
1314 printf("\n");
1315 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1316 "locks_latency MIN/AVG/MAX",
1317 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1318 s->locks.latency.max, s->locks.latency.num);
1320 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1321 "reclock_ctdbd MIN/AVG/MAX",
1322 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1323 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1325 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1326 "reclock_recd MIN/AVG/MAX",
1327 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1328 s->reclock.recd.max, s->reclock.recd.num);
1330 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1331 "call_latency MIN/AVG/MAX",
1332 s->call_latency.min, LATENCY_AVG(s->call_latency),
1333 s->call_latency.max, s->call_latency.num);
1335 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1336 "childwrite_latency MIN/AVG/MAX",
1337 s->childwrite_latency.min,
1338 LATENCY_AVG(s->childwrite_latency),
1339 s->childwrite_latency.max, s->childwrite_latency.num);
1342 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1343 int argc, const char **argv)
1345 struct ctdb_statistics *stats;
1346 int ret;
1348 if (argc != 0) {
1349 usage("statistics");
1352 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1353 ctdb->cmd_pnn, TIMEOUT(), &stats);
1354 if (ret != 0) {
1355 return ret;
1358 if (options.machinereadable) {
1359 print_statistics_machine(stats, true);
1360 } else {
1361 print_statistics(stats);
1364 return 0;
1367 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1368 struct ctdb_context *ctdb,
1369 int argc, const char **argv)
1371 int ret;
1373 if (argc != 0) {
1374 usage("statisticsreset");
1377 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1378 ctdb->cmd_pnn, TIMEOUT());
1379 if (ret != 0) {
1380 return ret;
1383 return 0;
1386 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1387 int argc, const char **argv)
1389 struct ctdb_statistics_list *slist;
1390 int ret, count = 0, i;
1391 bool show_header = true;
1393 if (argc > 1) {
1394 usage("stats");
1397 if (argc == 1) {
1398 count = atoi(argv[0]);
1401 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1402 ctdb->cmd_pnn, TIMEOUT(), &slist);
1403 if (ret != 0) {
1404 return ret;
1407 for (i=0; i<slist->num; i++) {
1408 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1409 continue;
1411 if (options.machinereadable == 1) {
1412 print_statistics_machine(&slist->stats[i],
1413 show_header);
1414 show_header = false;
1415 } else {
1416 print_statistics(&slist->stats[i]);
1418 if (count > 0 && i == count) {
1419 break;
1423 return 0;
1426 static int ctdb_public_ip_cmp(const void *a, const void *b)
1428 const struct ctdb_public_ip *ip_a = a;
1429 const struct ctdb_public_ip *ip_b = b;
1431 return ctdb_sock_addr_cmp(&ip_a->addr, &ip_b->addr);
1434 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1435 struct ctdb_public_ip_list *ips,
1436 struct ctdb_public_ip_info **ipinfo,
1437 bool all_nodes)
1439 unsigned int i, j;
1440 char *conf, *avail, *active;
1442 if (options.machinereadable == 1) {
1443 printf("%s%s%s%s%s", options.sep,
1444 "Public IP", options.sep,
1445 "Node", options.sep);
1446 if (options.verbose == 1) {
1447 printf("%s%s%s%s%s%s\n",
1448 "ActiveInterfaces", options.sep,
1449 "AvailableInterfaces", options.sep,
1450 "ConfiguredInterfaces", options.sep);
1451 } else {
1452 printf("\n");
1454 } else {
1455 if (all_nodes) {
1456 printf("Public IPs on ALL nodes\n");
1457 } else {
1458 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1462 for (i = 0; i < ips->num; i++) {
1464 if (options.machinereadable == 1) {
1465 printf("%s%s%s%d%s", options.sep,
1466 ctdb_sock_addr_to_string(
1467 mem_ctx, &ips->ip[i].addr, false),
1468 options.sep,
1469 (int)ips->ip[i].pnn, options.sep);
1470 } else {
1471 printf("%s", ctdb_sock_addr_to_string(
1472 mem_ctx, &ips->ip[i].addr, false));
1475 if (options.verbose == 0) {
1476 if (options.machinereadable == 1) {
1477 printf("\n");
1478 } else {
1479 printf(" %d\n", (int)ips->ip[i].pnn);
1481 continue;
1484 conf = NULL;
1485 avail = NULL;
1486 active = NULL;
1488 if (ipinfo[i] == NULL) {
1489 goto skip_ipinfo;
1492 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1493 struct ctdb_iface *iface;
1495 iface = &ipinfo[i]->ifaces->iface[j];
1496 if (conf == NULL) {
1497 conf = talloc_strdup(mem_ctx, iface->name);
1498 } else {
1499 conf = talloc_asprintf_append(
1500 conf, ",%s", iface->name);
1503 if (ipinfo[i]->active_idx == j) {
1504 active = iface->name;
1507 if (iface->link_state == 0) {
1508 continue;
1511 if (avail == NULL) {
1512 avail = talloc_strdup(mem_ctx, iface->name);
1513 } else {
1514 avail = talloc_asprintf_append(
1515 avail, ",%s", iface->name);
1519 skip_ipinfo:
1521 if (options.machinereadable == 1) {
1522 printf("%s%s%s%s%s%s\n",
1523 active ? active : "", options.sep,
1524 avail ? avail : "", options.sep,
1525 conf ? conf : "", options.sep);
1526 } else {
1527 printf(" node[%d] active[%s] available[%s]"
1528 " configured[%s]\n",
1529 (int)ips->ip[i].pnn, active ? active : "",
1530 avail ? avail : "", conf ? conf : "");
1535 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1536 size_t datalen, void *private_data)
1538 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1539 private_data, struct ctdb_public_ip_list);
1540 struct ctdb_public_ip *ip;
1542 ip = (struct ctdb_public_ip *)databuf;
1543 ips->ip[ips->num] = *ip;
1544 ips->num += 1;
1546 return 0;
1549 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1550 struct ctdb_public_ip_list **out)
1552 struct ctdb_node_map *nodemap;
1553 struct ctdb_public_ip_list *ips;
1554 struct db_hash_context *ipdb;
1555 uint32_t *pnn_list;
1556 unsigned int j;
1557 int ret, count, i;
1559 nodemap = get_nodemap(ctdb, false);
1560 if (nodemap == NULL) {
1561 return 1;
1564 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1565 if (ret != 0) {
1566 goto failed;
1569 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1570 &pnn_list);
1571 if (count <= 0) {
1572 goto failed;
1575 for (i=0; i<count; i++) {
1576 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1577 pnn_list[i], TIMEOUT(),
1578 false, &ips);
1579 if (ret != 0) {
1580 goto failed;
1583 for (j=0; j<ips->num; j++) {
1584 struct ctdb_public_ip ip;
1586 ip.pnn = ips->ip[j].pnn;
1587 ip.addr = ips->ip[j].addr;
1589 if (pnn_list[i] == ip.pnn) {
1590 /* Node claims IP is hosted on it, so
1591 * save that information
1593 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1594 sizeof(ip.addr),
1595 (uint8_t *)&ip, sizeof(ip));
1596 if (ret != 0) {
1597 goto failed;
1599 } else {
1600 /* Node thinks IP is hosted elsewhere,
1601 * so overwrite with CTDB_UNKNOWN_PNN
1602 * if there's no existing entry
1604 ret = db_hash_exists(ipdb, (uint8_t *)&ip.addr,
1605 sizeof(ip.addr));
1606 if (ret == ENOENT) {
1607 ip.pnn = CTDB_UNKNOWN_PNN;
1608 ret = db_hash_add(ipdb,
1609 (uint8_t *)&ip.addr,
1610 sizeof(ip.addr),
1611 (uint8_t *)&ip,
1612 sizeof(ip));
1613 if (ret != 0) {
1614 goto failed;
1620 TALLOC_FREE(ips);
1623 talloc_free(pnn_list);
1625 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1626 if (ret != 0) {
1627 goto failed;
1630 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1631 if (ips == NULL) {
1632 goto failed;
1635 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1636 if (ips->ip == NULL) {
1637 goto failed;
1640 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1641 if (ret != 0) {
1642 goto failed;
1645 if ((unsigned int)count != ips->num) {
1646 goto failed;
1649 talloc_free(ipdb);
1651 *out = ips;
1652 return 0;
1654 failed:
1655 talloc_free(ipdb);
1656 return 1;
1659 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1660 int argc, const char **argv)
1662 struct ctdb_public_ip_list *ips;
1663 struct ctdb_public_ip_info **ipinfo;
1664 unsigned int i;
1665 int ret;
1666 bool do_all = false;
1668 if (argc > 1) {
1669 usage("ip");
1672 if (argc == 1) {
1673 if (strcmp(argv[0], "all") == 0) {
1674 do_all = true;
1675 } else {
1676 usage("ip");
1680 if (do_all) {
1681 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1682 } else {
1683 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1684 ctdb->cmd_pnn, TIMEOUT(),
1685 false, &ips);
1687 if (ret != 0) {
1688 return ret;
1691 qsort(ips->ip, ips->num, sizeof(struct ctdb_public_ip),
1692 ctdb_public_ip_cmp);
1694 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1695 if (ipinfo == NULL) {
1696 return 1;
1699 for (i=0; i<ips->num; i++) {
1700 uint32_t pnn;
1701 if (do_all) {
1702 pnn = ips->ip[i].pnn;
1703 } else {
1704 pnn = ctdb->cmd_pnn;
1706 if (pnn == CTDB_UNKNOWN_PNN) {
1707 ipinfo[i] = NULL;
1708 continue;
1710 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1711 ctdb->client, pnn,
1712 TIMEOUT(), &ips->ip[i].addr,
1713 &ipinfo[i]);
1714 if (ret != 0) {
1715 return ret;
1719 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1720 return 0;
1723 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1724 int argc, const char **argv)
1726 struct ctdb_public_ip_info *ipinfo;
1727 ctdb_sock_addr addr;
1728 unsigned int i;
1729 int ret;
1731 if (argc != 1) {
1732 usage("ipinfo");
1735 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
1736 if (ret != 0) {
1737 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1738 return 1;
1741 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1742 ctdb->cmd_pnn, TIMEOUT(), &addr,
1743 &ipinfo);
1744 if (ret != 0) {
1745 if (ret == -1) {
1746 printf("Node %u does not know about IP %s\n",
1747 ctdb->cmd_pnn, argv[0]);
1749 return ret;
1752 printf("Public IP[%s] info on node %u\n",
1753 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1754 ctdb->cmd_pnn);
1756 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1757 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr, false),
1758 ipinfo->ip.pnn, ipinfo->ifaces->num);
1760 for (i=0; i<ipinfo->ifaces->num; i++) {
1761 struct ctdb_iface *iface;
1763 iface = &ipinfo->ifaces->iface[i];
1764 iface->name[CTDB_IFACE_SIZE] = '\0';
1765 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1766 i+1, iface->name,
1767 iface->link_state == 0 ? "down" : "up",
1768 iface->references,
1769 (i == ipinfo->active_idx) ? " (active)" : "");
1772 return 0;
1775 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1776 int argc, const char **argv)
1778 struct ctdb_iface_list *ifaces;
1779 unsigned int i;
1780 int ret;
1782 if (argc != 0) {
1783 usage("ifaces");
1786 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1787 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1788 if (ret != 0) {
1789 return ret;
1792 if (ifaces->num == 0) {
1793 printf("No interfaces configured on node %u\n",
1794 ctdb->cmd_pnn);
1795 return 0;
1798 if (options.machinereadable) {
1799 printf("%s%s%s%s%s%s%s\n", options.sep,
1800 "Name", options.sep,
1801 "LinkStatus", options.sep,
1802 "References", options.sep);
1803 } else {
1804 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1807 for (i=0; i<ifaces->num; i++) {
1808 if (options.machinereadable) {
1809 printf("%s%s%s%u%s%u%s\n", options.sep,
1810 ifaces->iface[i].name, options.sep,
1811 ifaces->iface[i].link_state, options.sep,
1812 ifaces->iface[i].references, options.sep);
1813 } else {
1814 printf("name:%s link:%s references:%u\n",
1815 ifaces->iface[i].name,
1816 ifaces->iface[i].link_state ? "up" : "down",
1817 ifaces->iface[i].references);
1821 return 0;
1824 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1825 int argc, const char **argv)
1827 struct ctdb_iface_list *ifaces;
1828 struct ctdb_iface *iface;
1829 unsigned int i;
1830 int ret;
1832 if (argc != 2) {
1833 usage("setifacelink");
1836 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1837 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1838 return 1;
1841 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1842 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1843 if (ret != 0) {
1844 fprintf(stderr,
1845 "Failed to get interface information from node %u\n",
1846 ctdb->cmd_pnn);
1847 return ret;
1850 iface = NULL;
1851 for (i=0; i<ifaces->num; i++) {
1852 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1853 iface = &ifaces->iface[i];
1854 break;
1858 if (iface == NULL) {
1859 printf("Interface %s not configured on node %u\n",
1860 argv[0], ctdb->cmd_pnn);
1861 return 1;
1864 if (strcmp(argv[1], "up") == 0) {
1865 iface->link_state = 1;
1866 } else if (strcmp(argv[1], "down") == 0) {
1867 iface->link_state = 0;
1868 } else {
1869 usage("setifacelink");
1870 return 1;
1873 iface->references = 0;
1875 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1876 ctdb->cmd_pnn, TIMEOUT(), iface);
1877 if (ret != 0) {
1878 return ret;
1881 return 0;
1884 static int control_process_exists(TALLOC_CTX *mem_ctx,
1885 struct ctdb_context *ctdb,
1886 int argc, const char **argv)
1888 pid_t pid;
1889 uint64_t srvid = 0;
1890 int status;
1891 int ret = 0;
1893 if (argc != 1 && argc != 2) {
1894 usage("process-exists");
1897 pid = atoi(argv[0]);
1898 if (argc == 2) {
1899 srvid = smb_strtoull(argv[1], NULL, 0, &ret, SMB_STR_STANDARD);
1900 if (ret != 0) {
1901 return ret;
1905 if (srvid == 0) {
1906 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1907 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1908 } else {
1909 struct ctdb_pid_srvid pid_srvid;
1911 pid_srvid.pid = pid;
1912 pid_srvid.srvid = srvid;
1914 ret = ctdb_ctrl_check_pid_srvid(mem_ctx, ctdb->ev,
1915 ctdb->client, ctdb->cmd_pnn,
1916 TIMEOUT(), &pid_srvid,
1917 &status);
1920 if (ret != 0) {
1921 return ret;
1924 if (srvid == 0) {
1925 printf("PID %d %s\n", pid,
1926 (status == 0 ? "exists" : "does not exist"));
1927 } else {
1928 printf("PID %d with SRVID 0x%"PRIx64" %s\n", pid, srvid,
1929 (status == 0 ? "exists" : "does not exist"));
1931 return status;
1934 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1935 int argc, const char **argv)
1937 struct ctdb_dbid_map *dbmap;
1938 unsigned int i;
1939 int ret;
1941 if (argc != 0) {
1942 usage("getdbmap");
1945 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1946 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1947 if (ret != 0) {
1948 return ret;
1951 if (options.machinereadable == 1) {
1952 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1953 options.sep,
1954 "ID", options.sep,
1955 "Name", options.sep,
1956 "Path", options.sep,
1957 "Persistent", options.sep,
1958 "Sticky", options.sep,
1959 "Unhealthy", options.sep,
1960 "Readonly", options.sep,
1961 "Replicated", options.sep);
1962 } else {
1963 printf("Number of databases:%d\n", dbmap->num);
1966 for (i=0; i<dbmap->num; i++) {
1967 const char *name;
1968 const char *path;
1969 const char *health;
1970 bool persistent;
1971 bool readonly;
1972 bool sticky;
1973 bool replicated;
1974 uint32_t db_id;
1976 db_id = dbmap->dbs[i].db_id;
1978 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1979 ctdb->cmd_pnn, TIMEOUT(), db_id,
1980 &name);
1981 if (ret != 0) {
1982 return ret;
1985 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1986 ctdb->cmd_pnn, TIMEOUT(), db_id,
1987 &path);
1988 if (ret != 0) {
1989 return ret;
1992 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1993 ctdb->cmd_pnn, TIMEOUT(), db_id,
1994 &health);
1995 if (ret != 0) {
1996 return ret;
1999 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
2000 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
2001 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
2002 replicated = dbmap->dbs[i].flags & CTDB_DB_FLAGS_REPLICATED;
2004 if (options.machinereadable == 1) {
2005 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2006 options.sep,
2007 db_id, options.sep,
2008 name, options.sep,
2009 path, options.sep,
2010 !! (persistent), options.sep,
2011 !! (sticky), options.sep,
2012 !! (health), options.sep,
2013 !! (readonly), options.sep,
2014 !! (replicated), options.sep);
2015 } else {
2016 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2017 db_id, name, path,
2018 persistent ? " PERSISTENT" : "",
2019 sticky ? " STICKY" : "",
2020 readonly ? " READONLY" : "",
2021 replicated ? " REPLICATED" : "",
2022 health ? " UNHEALTHY" : "");
2025 talloc_free(discard_const(name));
2026 talloc_free(discard_const(path));
2027 talloc_free(discard_const(health));
2030 return 0;
2033 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2034 int argc, const char **argv)
2036 uint32_t db_id;
2037 const char *db_name, *db_path, *db_health;
2038 uint8_t db_flags;
2039 int ret;
2041 if (argc != 1) {
2042 usage("getdbstatus");
2045 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2046 return 1;
2049 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
2050 ctdb->cmd_pnn, TIMEOUT(), db_id,
2051 &db_path);
2052 if (ret != 0) {
2053 return ret;
2056 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
2057 ctdb->cmd_pnn, TIMEOUT(), db_id,
2058 &db_health);
2059 if (ret != 0) {
2060 return ret;
2063 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
2064 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2065 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
2066 (db_flags & CTDB_DB_FLAGS_REPLICATED ? "yes" : "no"),
2067 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
2068 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"));
2069 printf("HEALTH: %s\n", (db_health ? db_health : "OK"));
2070 return 0;
2073 struct dump_record_state {
2074 uint32_t count;
2077 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2079 static void dump_tdb_data(const char *name, TDB_DATA val)
2081 size_t i;
2083 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
2084 for (i=0; i<val.dsize; i++) {
2085 if (ISASCII(val.dptr[i])) {
2086 fprintf(stdout, "%c", val.dptr[i]);
2087 } else {
2088 fprintf(stdout, "\\%02X", val.dptr[i]);
2091 fprintf(stdout, "\"\n");
2094 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
2096 fprintf(stdout, "dmaster: %u\n", header->dmaster);
2097 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
2098 fprintf(stdout, "flags: 0x%08x", header->flags);
2099 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
2100 fprintf(stdout, " MIGRATED_WITH_DATA");
2102 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
2103 fprintf(stdout, " VACUUM_MIGRATED");
2105 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
2106 fprintf(stdout, " AUTOMATIC");
2108 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
2109 fprintf(stdout, " RO_HAVE_DELEGATIONS");
2111 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
2112 fprintf(stdout, " RO_HAVE_READONLY");
2114 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
2115 fprintf(stdout, " RO_REVOKING_READONLY");
2117 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
2118 fprintf(stdout, " RO_REVOKE_COMPLETE");
2120 fprintf(stdout, "\n");
2124 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
2125 TDB_DATA key, TDB_DATA data, void *private_data)
2127 struct dump_record_state *state =
2128 (struct dump_record_state *)private_data;
2130 state->count += 1;
2132 dump_tdb_data("key", key);
2133 dump_ltdb_header(header);
2134 dump_tdb_data("data", data);
2135 fprintf(stdout, "\n");
2137 return 0;
2140 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2141 int argc, const char **argv)
2143 struct ctdb_db_context *db;
2144 const char *db_name;
2145 uint32_t db_id;
2146 uint8_t db_flags;
2147 struct dump_record_state state;
2148 int ret;
2150 if (argc != 1) {
2151 usage("catdb");
2154 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2155 return 1;
2158 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2159 db_flags, &db);
2160 if (ret != 0) {
2161 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2162 return ret;
2165 state.count = 0;
2167 ret = ctdb_db_traverse(mem_ctx, ctdb->ev, ctdb->client, db,
2168 ctdb->cmd_pnn, TIMEOUT(),
2169 dump_record, &state);
2171 printf("Dumped %u records\n", state.count);
2173 return ret;
2176 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2177 int argc, const char **argv)
2179 struct ctdb_db_context *db;
2180 const char *db_name;
2181 uint32_t db_id;
2182 uint8_t db_flags;
2183 struct dump_record_state state;
2184 int ret;
2186 if (argc != 1) {
2187 usage("cattdb");
2190 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2191 return 1;
2194 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2195 db_flags, &db);
2196 if (ret != 0) {
2197 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2198 return ret;
2201 state.count = 0;
2202 ret = ctdb_db_traverse_local(db, true, true, dump_record, &state);
2204 printf("Dumped %u record(s)\n", state.count);
2206 return ret;
2209 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2210 struct ctdb_context *ctdb,
2211 int argc, const char **argv)
2213 uint32_t caps;
2214 int ret;
2216 if (argc != 0) {
2217 usage("getcapabilities");
2220 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2221 ctdb->cmd_pnn, TIMEOUT(), &caps);
2222 if (ret != 0) {
2223 return ret;
2226 if (options.machinereadable == 1) {
2227 printf("%s%s%s%s%s\n",
2228 options.sep,
2229 "RECMASTER", options.sep,
2230 "LMASTER", options.sep);
2231 printf("%s%d%s%d%s\n", options.sep,
2232 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2233 !! (caps & CTDB_CAP_LMASTER), options.sep);
2234 } else {
2235 printf("RECMASTER: %s\n",
2236 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2237 printf("LMASTER: %s\n",
2238 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2241 return 0;
2244 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2245 int argc, const char **argv)
2247 printf("%u\n", ctdb_client_pnn(ctdb->client));
2248 return 0;
2251 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2252 int argc, const char **argv)
2254 char *t, *lvs_helper = NULL;
2256 if (argc != 1) {
2257 usage("lvs");
2260 t = getenv("CTDB_LVS_HELPER");
2261 if (t != NULL) {
2262 lvs_helper = talloc_strdup(mem_ctx, t);
2263 } else {
2264 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2265 CTDB_HELPER_BINDIR);
2268 if (lvs_helper == NULL) {
2269 fprintf(stderr, "Unable to set LVS helper\n");
2270 return 1;
2273 return run_helper(mem_ctx, "LVS helper", lvs_helper, argc, argv);
2276 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2277 int argc, const char **argv)
2279 int log_level;
2280 int ret;
2281 bool found;
2283 if (argc != 1) {
2284 usage("setdebug");
2287 found = debug_level_parse(argv[0], &log_level);
2288 if (! found) {
2289 fprintf(stderr,
2290 "Invalid debug level '%s'. Valid levels are:\n",
2291 argv[0]);
2292 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2293 return 1;
2296 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2297 ctdb->cmd_pnn, TIMEOUT(), log_level);
2298 if (ret != 0) {
2299 return ret;
2302 return 0;
2305 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2306 int argc, const char **argv)
2308 int loglevel;
2309 const char *log_str;
2310 int ret;
2312 if (argc != 0) {
2313 usage("getdebug");
2316 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2317 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2318 if (ret != 0) {
2319 return ret;
2322 log_str = debug_level_to_string(loglevel);
2323 printf("%s\n", log_str);
2325 return 0;
2328 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2329 int argc, const char **argv)
2331 const char *db_name;
2332 uint8_t db_flags = 0;
2333 int ret;
2335 if (argc < 1 || argc > 2) {
2336 usage("attach");
2339 db_name = argv[0];
2340 if (argc == 2) {
2341 if (strcmp(argv[1], "persistent") == 0) {
2342 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2343 } else if (strcmp(argv[1], "readonly") == 0) {
2344 db_flags = CTDB_DB_FLAGS_READONLY;
2345 } else if (strcmp(argv[1], "sticky") == 0) {
2346 db_flags = CTDB_DB_FLAGS_STICKY;
2347 } else if (strcmp(argv[1], "replicated") == 0) {
2348 db_flags = CTDB_DB_FLAGS_REPLICATED;
2349 } else {
2350 usage("attach");
2354 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2355 db_flags, NULL);
2356 if (ret != 0) {
2357 return ret;
2360 return 0;
2363 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2364 int argc, const char **argv)
2366 const char *db_name;
2367 uint32_t db_id;
2368 uint8_t db_flags;
2369 struct ctdb_node_map *nodemap;
2370 int recmode;
2371 unsigned int j;
2372 int ret, ret2, i;
2374 if (argc < 1) {
2375 usage("detach");
2378 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2379 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2380 if (ret != 0) {
2381 return ret;
2384 if (recmode == CTDB_RECOVERY_ACTIVE) {
2385 fprintf(stderr, "Database cannot be detached"
2386 " when recovery is active\n");
2387 return 1;
2390 nodemap = get_nodemap(ctdb, false);
2391 if (nodemap == NULL) {
2392 return 1;
2395 for (j=0; j<nodemap->num; j++) {
2396 uint32_t value;
2398 if (nodemap->node[j].flags & NODE_FLAGS_DISCONNECTED) {
2399 continue;
2401 if (nodemap->node[j].flags & NODE_FLAGS_DELETED) {
2402 continue;
2404 if (nodemap->node[j].flags & NODE_FLAGS_INACTIVE) {
2405 fprintf(stderr, "Database cannot be detached on"
2406 " inactive (stopped or banned) node %u\n",
2407 nodemap->node[j].pnn);
2408 return 1;
2411 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2412 nodemap->node[j].pnn, TIMEOUT(),
2413 "AllowClientDBAttach", &value);
2414 if (ret != 0) {
2415 fprintf(stderr,
2416 "Unable to get tunable AllowClientDBAttach"
2417 " from node %u\n", nodemap->node[j].pnn);
2418 return ret;
2421 if (value == 1) {
2422 fprintf(stderr,
2423 "Database access is still active on node %u."
2424 " Set AllowclientDBAttach=0 on all nodes.\n",
2425 nodemap->node[j].pnn);
2426 return 1;
2430 ret2 = 0;
2431 for (i=0; i<argc; i++) {
2432 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2433 &db_flags)) {
2434 continue;
2437 if (db_flags &
2438 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
2439 fprintf(stderr,
2440 "Only volatile databases can be detached\n");
2441 return 1;
2444 ret = ctdb_detach(ctdb->ev, ctdb->client, TIMEOUT(), db_id);
2445 if (ret != 0) {
2446 fprintf(stderr, "Database %s detach failed\n", db_name);
2447 ret2 = ret;
2451 return ret2;
2454 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2455 int argc, const char **argv)
2457 const char *mem_str;
2458 ssize_t n;
2459 int ret;
2461 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2462 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2463 if (ret != 0) {
2464 return ret;
2467 n = write(1, mem_str, strlen(mem_str));
2468 if (n < 0 || (size_t)n != strlen(mem_str)) {
2469 fprintf(stderr, "Failed to write talloc summary\n");
2470 return 1;
2473 return 0;
2476 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2478 bool *done = (bool *)private_data;
2479 size_t len;
2480 ssize_t n;
2482 len = strnlen((const char *)data.dptr, data.dsize);
2483 n = write(1, data.dptr, len);
2484 if (n < 0 || (size_t)n != len) {
2485 fprintf(stderr, "Failed to write talloc summary\n");
2488 *done = true;
2491 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2492 int argc, const char **argv)
2494 struct ctdb_srvid_message msg = { 0 };
2495 int ret;
2496 bool done = false;
2498 msg.pnn = ctdb->pnn;
2499 msg.srvid = next_srvid(ctdb);
2501 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2502 msg.srvid, dump_memory, &done);
2503 if (ret != 0) {
2504 return ret;
2507 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2508 ctdb->cmd_pnn, &msg);
2509 if (ret != 0) {
2510 return ret;
2513 ctdb_client_wait(ctdb->ev, &done);
2514 return 0;
2517 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2518 int argc, const char **argv)
2520 pid_t pid;
2521 int ret;
2523 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2524 ctdb->cmd_pnn, TIMEOUT(), &pid);
2525 if (ret != 0) {
2526 return ret;
2529 printf("%u\n", pid);
2530 return 0;
2533 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2534 const char *desc, uint32_t flag, bool set_flag)
2536 struct ctdb_node_map *nodemap;
2537 bool flag_is_set;
2539 nodemap = get_nodemap(ctdb, false);
2540 if (nodemap == NULL) {
2541 return 1;
2544 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2545 if (set_flag == flag_is_set) {
2546 if (set_flag) {
2547 fprintf(stderr, "Node %u is already %s\n",
2548 ctdb->cmd_pnn, desc);
2549 } else {
2550 fprintf(stderr, "Node %u is not %s\n",
2551 ctdb->cmd_pnn, desc);
2553 return 0;
2556 return 1;
2559 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2560 uint32_t flag, bool set_flag)
2562 struct ctdb_node_map *nodemap;
2563 bool flag_is_set;
2565 while (1) {
2566 nodemap = get_nodemap(ctdb, true);
2567 if (nodemap == NULL) {
2568 fprintf(stderr,
2569 "Failed to get nodemap, trying again\n");
2570 sleep(1);
2571 continue;
2574 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2575 if (flag_is_set == set_flag) {
2576 break;
2579 sleep(1);
2583 static int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2584 struct ctdb_client_context *client,
2585 uint32_t destnode, struct timeval timeout,
2586 uint32_t set, uint32_t clear)
2588 struct ctdb_node_map *nodemap;
2589 struct ctdb_node_flag_change flag_change;
2590 struct ctdb_req_control request;
2591 uint32_t *pnn_list;
2592 int ret, count;
2594 ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode,
2595 tevent_timeval_zero(), &nodemap);
2596 if (ret != 0) {
2597 return ret;
2600 flag_change.pnn = destnode;
2601 flag_change.old_flags = nodemap->node[destnode].flags;
2602 flag_change.new_flags = flag_change.old_flags | set;
2603 flag_change.new_flags &= ~clear;
2605 count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
2606 if (count == -1) {
2607 return ENOMEM;
2610 ctdb_req_control_modify_flags(&request, &flag_change);
2611 ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
2612 tevent_timeval_zero(), &request,
2613 NULL, NULL);
2614 return ret;
2617 struct ipreallocate_state {
2618 int status;
2619 bool done;
2622 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2623 void *private_data)
2625 struct ipreallocate_state *state =
2626 (struct ipreallocate_state *)private_data;
2628 if (data.dsize != sizeof(int)) {
2629 /* Ignore packet */
2630 return;
2633 state->status = *(int *)data.dptr;
2634 state->done = true;
2637 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2639 struct ctdb_srvid_message msg = { 0 };
2640 struct ipreallocate_state state;
2641 int ret;
2643 msg.pnn = ctdb->pnn;
2644 msg.srvid = next_srvid(ctdb);
2646 state.done = false;
2647 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2648 msg.srvid,
2649 ipreallocate_handler, &state);
2650 if (ret != 0) {
2651 return ret;
2654 while (true) {
2655 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2656 ctdb->client,
2657 CTDB_BROADCAST_CONNECTED,
2658 &msg);
2659 if (ret != 0) {
2660 goto fail;
2663 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2664 TIMEOUT());
2665 if (ret != 0) {
2666 continue;
2669 if (state.status >= 0) {
2670 ret = 0;
2671 } else {
2672 ret = state.status;
2674 break;
2677 fail:
2678 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2679 msg.srvid, &state);
2680 return ret;
2683 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2684 int argc, const char **argv)
2686 int ret;
2688 if (argc != 0) {
2689 usage("disable");
2692 ret = check_flags(mem_ctx, ctdb, "disabled",
2693 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2694 if (ret == 0) {
2695 return 0;
2698 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2699 ctdb->cmd_pnn, TIMEOUT(),
2700 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2701 if (ret != 0) {
2702 fprintf(stderr,
2703 "Failed to set DISABLED flag on node %u\n",
2704 ctdb->cmd_pnn);
2705 return ret;
2708 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2709 return ipreallocate(mem_ctx, ctdb);
2712 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2713 int argc, const char **argv)
2715 int ret;
2717 if (argc != 0) {
2718 usage("enable");
2721 ret = check_flags(mem_ctx, ctdb, "disabled",
2722 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2723 if (ret == 0) {
2724 return 0;
2727 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2728 ctdb->cmd_pnn, TIMEOUT(),
2729 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2730 if (ret != 0) {
2731 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2732 ctdb->cmd_pnn);
2733 return ret;
2736 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2737 return ipreallocate(mem_ctx, ctdb);
2740 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2741 int argc, const char **argv)
2743 int ret;
2745 if (argc != 0) {
2746 usage("stop");
2749 ret = check_flags(mem_ctx, ctdb, "stopped",
2750 NODE_FLAGS_STOPPED, true);
2751 if (ret == 0) {
2752 return 0;
2755 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2756 ctdb->cmd_pnn, TIMEOUT());
2757 if (ret != 0) {
2758 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2759 return ret;
2762 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2763 return ipreallocate(mem_ctx, ctdb);
2766 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2767 int argc, const char **argv)
2769 int ret;
2771 if (argc != 0) {
2772 usage("continue");
2775 ret = check_flags(mem_ctx, ctdb, "stopped",
2776 NODE_FLAGS_STOPPED, false);
2777 if (ret == 0) {
2778 return 0;
2781 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2782 ctdb->cmd_pnn, TIMEOUT());
2783 if (ret != 0) {
2784 fprintf(stderr, "Failed to continue stopped node %u\n",
2785 ctdb->cmd_pnn);
2786 return ret;
2789 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2790 return ipreallocate(mem_ctx, ctdb);
2793 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2794 int argc, const char **argv)
2796 struct ctdb_ban_state ban_state;
2797 int ret = 0;
2799 if (argc != 1) {
2800 usage("ban");
2803 ret = check_flags(mem_ctx, ctdb, "banned",
2804 NODE_FLAGS_BANNED, true);
2805 if (ret == 0) {
2806 return 0;
2809 ban_state.pnn = ctdb->cmd_pnn;
2810 ban_state.time = smb_strtoul(argv[0], NULL, 0, &ret, SMB_STR_STANDARD);
2811 if (ret != 0) {
2812 return ret;
2815 if (ban_state.time == 0) {
2816 fprintf(stderr, "Ban time cannot be zero\n");
2817 return EINVAL;
2820 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2821 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2822 if (ret != 0) {
2823 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2824 return ret;
2827 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2828 return ipreallocate(mem_ctx, ctdb);
2832 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2833 int argc, const char **argv)
2835 struct ctdb_ban_state ban_state;
2836 int ret;
2838 if (argc != 0) {
2839 usage("unban");
2842 ret = check_flags(mem_ctx, ctdb, "banned",
2843 NODE_FLAGS_BANNED, false);
2844 if (ret == 0) {
2845 return 0;
2848 ban_state.pnn = ctdb->cmd_pnn;
2849 ban_state.time = 0;
2851 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2852 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2853 if (ret != 0) {
2854 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2855 return ret;
2858 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2859 return ipreallocate(mem_ctx, ctdb);
2863 static void wait_for_shutdown(void *private_data)
2865 bool *done = (bool *)private_data;
2867 *done = true;
2870 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2871 int argc, const char **argv)
2873 int ret;
2874 bool done = false;
2876 if (argc != 0) {
2877 usage("shutdown");
2880 if (ctdb->pnn == ctdb->cmd_pnn) {
2881 ctdb_client_set_disconnect_callback(ctdb->client,
2882 wait_for_shutdown,
2883 &done);
2886 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2887 ctdb->cmd_pnn, TIMEOUT());
2888 if (ret != 0) {
2889 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2890 return ret;
2893 if (ctdb->pnn == ctdb->cmd_pnn) {
2894 ctdb_client_wait(ctdb->ev, &done);
2897 return 0;
2900 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2901 uint32_t *generation)
2903 uint32_t recmaster;
2904 int recmode;
2905 struct ctdb_vnn_map *vnnmap;
2906 int ret;
2908 again:
2909 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2910 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2911 if (ret != 0) {
2912 fprintf(stderr, "Failed to find recovery master\n");
2913 return ret;
2916 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2917 recmaster, TIMEOUT(), &recmode);
2918 if (ret != 0) {
2919 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2920 recmaster);
2921 return ret;
2924 if (recmode == CTDB_RECOVERY_ACTIVE) {
2925 sleep(1);
2926 goto again;
2929 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2930 recmaster, TIMEOUT(), &vnnmap);
2931 if (ret != 0) {
2932 fprintf(stderr, "Failed to get generation from node %u\n",
2933 recmaster);
2934 return ret;
2937 if (vnnmap->generation == INVALID_GENERATION) {
2938 talloc_free(vnnmap);
2939 sleep(1);
2940 goto again;
2943 *generation = vnnmap->generation;
2944 talloc_free(vnnmap);
2945 return 0;
2949 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2950 int argc, const char **argv)
2952 uint32_t generation, next_generation;
2953 int ret;
2955 if (argc != 0) {
2956 usage("recover");
2959 ret = get_generation(mem_ctx, ctdb, &generation);
2960 if (ret != 0) {
2961 return ret;
2964 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2965 ctdb->cmd_pnn, TIMEOUT(),
2966 CTDB_RECOVERY_ACTIVE);
2967 if (ret != 0) {
2968 fprintf(stderr, "Failed to set recovery mode active\n");
2969 return ret;
2972 while (1) {
2973 ret = get_generation(mem_ctx, ctdb, &next_generation);
2974 if (ret != 0) {
2975 fprintf(stderr,
2976 "Failed to confirm end of recovery\n");
2977 return ret;
2980 if (next_generation != generation) {
2981 break;
2984 sleep (1);
2987 return 0;
2990 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2991 int argc, const char **argv)
2993 if (argc != 0) {
2994 usage("ipreallocate");
2997 return ipreallocate(mem_ctx, ctdb);
3000 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3001 int argc, const char **argv)
3003 struct ctdb_addr_info addr_info;
3004 int ret;
3006 if (argc != 2) {
3007 usage("gratarp");
3010 ret = ctdb_sock_addr_from_string(argv[0], &addr_info.addr, false);
3011 if (ret != 0) {
3012 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3013 return 1;
3015 addr_info.iface = argv[1];
3017 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
3018 ctdb->cmd_pnn, TIMEOUT(),
3019 &addr_info);
3020 if (ret != 0) {
3021 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
3022 ctdb->cmd_pnn);
3023 return ret;
3026 return 0;
3029 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3030 int argc, const char **argv)
3032 ctdb_sock_addr src, dst;
3033 int ret;
3035 if (argc != 0 && argc != 2) {
3036 usage("tickle");
3039 if (argc == 0) {
3040 struct ctdb_connection_list *clist;
3041 unsigned int i;
3042 unsigned int num_failed;
3044 /* Client first but the src/dst logic is confused */
3045 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3046 if (ret != 0) {
3047 return ret;
3050 num_failed = 0;
3051 for (i = 0; i < clist->num; i++) {
3052 ret = ctdb_sys_send_tcp(&clist->conn[i].src,
3053 &clist->conn[i].dst,
3054 0, 0, 0);
3055 if (ret != 0) {
3056 num_failed += 1;
3060 TALLOC_FREE(clist);
3062 if (num_failed > 0) {
3063 fprintf(stderr, "Failed to send %d tickles\n",
3064 num_failed);
3065 return 1;
3068 return 0;
3072 ret = ctdb_sock_addr_from_string(argv[0], &src, true);
3073 if (ret != 0) {
3074 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3075 return 1;
3078 ret = ctdb_sock_addr_from_string(argv[1], &dst, true);
3079 if (ret != 0) {
3080 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3081 return 1;
3084 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3085 if (ret != 0) {
3086 fprintf(stderr, "Failed to send tickle ack\n");
3087 return ret;
3090 return 0;
3093 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3094 int argc, const char **argv)
3096 ctdb_sock_addr addr;
3097 struct ctdb_tickle_list *tickles;
3098 unsigned port = 0;
3099 unsigned int i;
3100 int ret = 0;
3102 if (argc < 1 || argc > 2) {
3103 usage("gettickles");
3106 if (argc == 2) {
3107 port = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3108 if (ret != 0) {
3109 return ret;
3113 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3114 if (ret != 0) {
3115 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3116 return 1;
3118 ctdb_sock_addr_set_port(&addr, port);
3120 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3121 ctdb->cmd_pnn, TIMEOUT(), &addr,
3122 &tickles);
3123 if (ret != 0) {
3124 fprintf(stderr, "Failed to get list of connections\n");
3125 return ret;
3128 if (options.machinereadable) {
3129 printf("%s%s%s%s%s%s%s%s%s\n",
3130 options.sep,
3131 "Source IP", options.sep,
3132 "Port", options.sep,
3133 "Destiation IP", options.sep,
3134 "Port", options.sep);
3135 for (i=0; i<tickles->num; i++) {
3136 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3137 ctdb_sock_addr_to_string(
3138 mem_ctx, &tickles->conn[i].src, false),
3139 options.sep,
3140 ntohs(tickles->conn[i].src.ip.sin_port),
3141 options.sep,
3142 ctdb_sock_addr_to_string(
3143 mem_ctx, &tickles->conn[i].dst, false),
3144 options.sep,
3145 ntohs(tickles->conn[i].dst.ip.sin_port),
3146 options.sep);
3148 } else {
3149 printf("Connections for IP: %s\n",
3150 ctdb_sock_addr_to_string(mem_ctx,
3151 &tickles->addr, false));
3152 printf("Num connections: %u\n", tickles->num);
3153 for (i=0; i<tickles->num; i++) {
3154 printf("SRC: %s DST: %s\n",
3155 ctdb_sock_addr_to_string(
3156 mem_ctx, &tickles->conn[i].src, true),
3157 ctdb_sock_addr_to_string(
3158 mem_ctx, &tickles->conn[i].dst, true));
3162 talloc_free(tickles);
3163 return 0;
3166 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3167 struct ctdb_connection *conn);
3169 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3171 struct process_clist_state {
3172 struct ctdb_connection_list *clist;
3173 int count;
3174 unsigned int num_failed, num_total;
3175 clist_reply_func reply_func;
3178 static void process_clist_done(struct tevent_req *subreq);
3180 static struct tevent_req *process_clist_send(
3181 TALLOC_CTX *mem_ctx,
3182 struct ctdb_context *ctdb,
3183 struct ctdb_connection_list *clist,
3184 clist_request_func request_func,
3185 clist_reply_func reply_func)
3187 struct tevent_req *req, *subreq;
3188 struct process_clist_state *state;
3189 struct ctdb_req_control request;
3190 unsigned int i;
3192 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3193 if (req == NULL) {
3194 return NULL;
3197 state->clist = clist;
3198 state->reply_func = reply_func;
3200 for (i = 0; i < clist->num; i++) {
3201 request_func(&request, &clist->conn[i]);
3202 subreq = ctdb_client_control_send(state, ctdb->ev,
3203 ctdb->client, ctdb->cmd_pnn,
3204 TIMEOUT(), &request);
3205 if (tevent_req_nomem(subreq, req)) {
3206 return tevent_req_post(req, ctdb->ev);
3208 tevent_req_set_callback(subreq, process_clist_done, req);
3211 return req;
3214 static void process_clist_done(struct tevent_req *subreq)
3216 struct tevent_req *req = tevent_req_callback_data(
3217 subreq, struct tevent_req);
3218 struct process_clist_state *state = tevent_req_data(
3219 req, struct process_clist_state);
3220 struct ctdb_reply_control *reply;
3221 int ret;
3222 bool status;
3224 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3225 TALLOC_FREE(subreq);
3226 if (! status) {
3227 state->num_failed += 1;
3228 goto done;
3231 ret = state->reply_func(reply);
3232 if (ret != 0) {
3233 state->num_failed += 1;
3234 goto done;
3237 done:
3238 state->num_total += 1;
3239 if (state->num_total == state->clist->num) {
3240 tevent_req_done(req);
3244 static int process_clist_recv(struct tevent_req *req)
3246 struct process_clist_state *state = tevent_req_data(
3247 req, struct process_clist_state);
3249 return state->num_failed;
3252 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3253 int argc, const char **argv)
3255 struct ctdb_connection conn;
3256 int ret;
3258 if (argc != 0 && argc != 2) {
3259 usage("addtickle");
3262 if (argc == 0) {
3263 struct ctdb_connection_list *clist;
3264 struct tevent_req *req;
3266 /* Client first but the src/dst logic is confused */
3267 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3268 if (ret != 0) {
3269 return ret;
3271 if (clist->num == 0) {
3272 return 0;
3275 req = process_clist_send(mem_ctx, ctdb, clist,
3276 ctdb_req_control_tcp_add_delayed_update,
3277 ctdb_reply_control_tcp_add_delayed_update);
3278 if (req == NULL) {
3279 talloc_free(clist);
3280 return ENOMEM;
3283 tevent_req_poll(req, ctdb->ev);
3284 talloc_free(clist);
3286 ret = process_clist_recv(req);
3287 if (ret != 0) {
3288 fprintf(stderr, "Failed to add %d tickles\n", ret);
3289 return 1;
3292 return 0;
3295 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3296 if (ret != 0) {
3297 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3298 return 1;
3300 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3301 if (ret != 0) {
3302 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3303 return 1;
3306 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3307 ctdb->client, ctdb->cmd_pnn,
3308 TIMEOUT(), &conn);
3309 if (ret != 0) {
3310 fprintf(stderr, "Failed to register connection\n");
3311 return ret;
3314 return 0;
3317 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3318 int argc, const char **argv)
3320 struct ctdb_connection conn;
3321 int ret;
3323 if (argc != 0 && argc != 2) {
3324 usage("deltickle");
3327 if (argc == 0) {
3328 struct ctdb_connection_list *clist;
3329 struct tevent_req *req;
3331 /* Client first but the src/dst logic is confused */
3332 ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist);
3333 if (ret != 0) {
3334 return ret;
3336 if (clist->num == 0) {
3337 return 0;
3340 req = process_clist_send(mem_ctx, ctdb, clist,
3341 ctdb_req_control_tcp_remove,
3342 ctdb_reply_control_tcp_remove);
3343 if (req == NULL) {
3344 talloc_free(clist);
3345 return ENOMEM;
3348 tevent_req_poll(req, ctdb->ev);
3349 talloc_free(clist);
3351 ret = process_clist_recv(req);
3352 if (ret != 0) {
3353 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3354 return 1;
3357 return 0;
3360 ret = ctdb_sock_addr_from_string(argv[0], &conn.src, true);
3361 if (ret != 0) {
3362 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3363 return 1;
3365 ret = ctdb_sock_addr_from_string(argv[1], &conn.dst, true);
3366 if (ret != 0) {
3367 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3368 return 1;
3371 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3372 ctdb->cmd_pnn, TIMEOUT(), &conn);
3373 if (ret != 0) {
3374 fprintf(stderr, "Failed to unregister connection\n");
3375 return ret;
3378 return 0;
3381 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3382 int argc, const char **argv)
3384 struct ctdb_node_map *nodemap;
3385 unsigned int i;
3387 if (argc != 0) {
3388 usage("listnodes");
3391 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3392 if (nodemap == NULL) {
3393 return 1;
3396 for (i=0; i<nodemap->num; i++) {
3397 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3398 continue;
3401 if (options.machinereadable) {
3402 printf("%s%u%s%s%s\n", options.sep,
3403 nodemap->node[i].pnn, options.sep,
3404 ctdb_sock_addr_to_string(
3405 mem_ctx, &nodemap->node[i].addr, false),
3406 options.sep);
3407 } else {
3408 printf("%s\n",
3409 ctdb_sock_addr_to_string(
3410 mem_ctx, &nodemap->node[i].addr, false));
3414 return 0;
3417 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3418 struct ctdb_node_map *nodemap2)
3420 unsigned int i;
3422 if (nodemap1->num != nodemap2->num) {
3423 return false;
3426 for (i=0; i<nodemap1->num; i++) {
3427 struct ctdb_node_and_flags *n1, *n2;
3429 n1 = &nodemap1->node[i];
3430 n2 = &nodemap2->node[i];
3432 if ((n1->pnn != n2->pnn) ||
3433 (n1->flags != n2->flags) ||
3434 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3435 return false;
3439 return true;
3442 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3443 struct ctdb_node_map *nm,
3444 struct ctdb_node_map *fnm,
3445 bool *reload)
3447 unsigned int i;
3448 bool check_failed = false;
3450 *reload = false;
3452 for (i=0; i<nm->num; i++) {
3453 if (i >= fnm->num) {
3454 fprintf(stderr,
3455 "Node %u (%s) missing from nodes file\n",
3456 nm->node[i].pnn,
3457 ctdb_sock_addr_to_string(
3458 mem_ctx, &nm->node[i].addr, false));
3459 check_failed = true;
3460 continue;
3462 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3463 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3464 /* Node remains deleted */
3465 continue;
3468 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3469 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3470 /* Node not newly nor previously deleted */
3471 if (! ctdb_same_ip(&nm->node[i].addr,
3472 &fnm->node[i].addr)) {
3473 fprintf(stderr,
3474 "Node %u has changed IP address"
3475 " (was %s, now %s)\n",
3476 nm->node[i].pnn,
3477 ctdb_sock_addr_to_string(
3478 mem_ctx,
3479 &nm->node[i].addr, false),
3480 ctdb_sock_addr_to_string(
3481 mem_ctx,
3482 &fnm->node[i].addr, false));
3483 check_failed = true;
3484 } else {
3485 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3486 fprintf(stderr,
3487 "WARNING: Node %u is disconnected."
3488 " You MUST fix this node manually!\n",
3489 nm->node[i].pnn);
3492 continue;
3495 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3496 /* Node is being deleted */
3497 printf("Node %u is DELETED\n", nm->node[i].pnn);
3498 *reload = true;
3499 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3500 fprintf(stderr,
3501 "ERROR: Node %u is still connected\n",
3502 nm->node[i].pnn);
3503 check_failed = true;
3505 continue;
3508 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3509 /* Node was previously deleted */
3510 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3511 *reload = true;
3515 if (check_failed) {
3516 fprintf(stderr,
3517 "ERROR: Nodes will not be reloaded due to previous error\n");
3518 return 1;
3521 /* Leftover nodes in file are NEW */
3522 for (; i < fnm->num; i++) {
3523 printf("Node %u is NEW\n", fnm->node[i].pnn);
3524 *reload = true;
3527 return 0;
3530 struct disable_recoveries_state {
3531 uint32_t *pnn_list;
3532 unsigned int node_count;
3533 bool *reply;
3534 int status;
3535 bool done;
3538 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3539 void *private_data)
3541 struct disable_recoveries_state *state =
3542 (struct disable_recoveries_state *)private_data;
3543 unsigned int i;
3544 int ret;
3546 if (data.dsize != sizeof(int)) {
3547 /* Ignore packet */
3548 return;
3551 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3552 ret = *(int *)data.dptr;
3553 if (ret < 0) {
3554 state->status = ret;
3555 state->done = true;
3556 return;
3558 for (i=0; i<state->node_count; i++) {
3559 if (state->pnn_list[i] == (uint32_t)ret) {
3560 state->reply[i] = true;
3561 break;
3565 state->done = true;
3566 for (i=0; i<state->node_count; i++) {
3567 if (! state->reply[i]) {
3568 state->done = false;
3569 break;
3574 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3575 uint32_t timeout, uint32_t *pnn_list, int count)
3577 struct ctdb_disable_message disable = { 0 };
3578 struct disable_recoveries_state state;
3579 int ret, i;
3581 disable.pnn = ctdb->pnn;
3582 disable.srvid = next_srvid(ctdb);
3583 disable.timeout = timeout;
3585 state.pnn_list = pnn_list;
3586 state.node_count = count;
3587 state.done = false;
3588 state.status = 0;
3589 state.reply = talloc_zero_array(mem_ctx, bool, count);
3590 if (state.reply == NULL) {
3591 return ENOMEM;
3594 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3595 disable.srvid,
3596 disable_recoveries_handler,
3597 &state);
3598 if (ret != 0) {
3599 return ret;
3602 for (i=0; i<count; i++) {
3603 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3604 ctdb->client,
3605 pnn_list[i],
3606 &disable);
3607 if (ret != 0) {
3608 goto fail;
3612 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3613 if (ret == ETIME) {
3614 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3615 } else {
3616 ret = (state.status >= 0 ? 0 : 1);
3619 fail:
3620 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3621 disable.srvid, &state);
3622 return ret;
3625 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3626 int argc, const char **argv)
3628 struct ctdb_node_map *nodemap = NULL;
3629 struct ctdb_node_map *file_nodemap;
3630 struct ctdb_node_map *remote_nodemap;
3631 struct ctdb_req_control request;
3632 struct ctdb_reply_control **reply;
3633 bool reload;
3634 unsigned int i;
3635 int count;
3636 int ret;
3637 uint32_t *pnn_list;
3639 nodemap = get_nodemap(ctdb, false);
3640 if (nodemap == NULL) {
3641 return 1;
3644 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3645 if (file_nodemap == NULL) {
3646 return 1;
3649 for (i=0; i<nodemap->num; i++) {
3650 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3651 continue;
3654 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3655 nodemap->node[i].pnn, TIMEOUT(),
3656 &remote_nodemap);
3657 if (ret != 0) {
3658 fprintf(stderr,
3659 "ERROR: Failed to get nodes file from node %u\n",
3660 nodemap->node[i].pnn);
3661 return ret;
3664 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3665 fprintf(stderr,
3666 "ERROR: Nodes file on node %u differs"
3667 " from current node (%u)\n",
3668 nodemap->node[i].pnn, ctdb->pnn);
3669 return 1;
3673 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3674 if (ret != 0) {
3675 return ret;
3678 if (! reload) {
3679 fprintf(stderr, "No change in nodes file,"
3680 " skipping unnecessary reload\n");
3681 return 0;
3684 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3685 mem_ctx, &pnn_list);
3686 if (count <= 0) {
3687 fprintf(stderr, "Memory allocation error\n");
3688 return 1;
3691 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3692 pnn_list, count);
3693 if (ret != 0) {
3694 fprintf(stderr, "Failed to disable recoveries\n");
3695 return ret;
3698 ctdb_req_control_reload_nodes_file(&request);
3699 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3700 pnn_list, count, TIMEOUT(),
3701 &request, NULL, &reply);
3702 if (ret != 0) {
3703 bool failed = false;
3704 int j;
3706 for (j=0; j<count; j++) {
3707 ret = ctdb_reply_control_reload_nodes_file(reply[j]);
3708 if (ret != 0) {
3709 fprintf(stderr,
3710 "Node %u failed to reload nodes\n",
3711 pnn_list[j]);
3712 failed = true;
3715 if (failed) {
3716 fprintf(stderr,
3717 "You MUST fix failed nodes manually!\n");
3721 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3722 if (ret != 0) {
3723 fprintf(stderr, "Failed to enable recoveries\n");
3724 return ret;
3727 return 0;
3730 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3731 ctdb_sock_addr *addr, uint32_t pnn)
3733 struct ctdb_public_ip_list *pubip_list;
3734 struct ctdb_public_ip pubip;
3735 struct ctdb_node_map *nodemap;
3736 struct ctdb_req_control request;
3737 uint32_t *pnn_list;
3738 unsigned int i;
3739 int ret, count;
3741 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3742 CTDB_BROADCAST_CONNECTED,
3743 2*options.timelimit);
3744 if (ret != 0) {
3745 fprintf(stderr, "Failed to disable IP check\n");
3746 return ret;
3749 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3750 pnn, TIMEOUT(), false, &pubip_list);
3751 if (ret != 0) {
3752 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3753 pnn);
3754 return ret;
3757 for (i=0; i<pubip_list->num; i++) {
3758 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3759 break;
3763 if (i == pubip_list->num) {
3764 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3765 pnn, ctdb_sock_addr_to_string(mem_ctx, addr, false));
3766 return 1;
3769 nodemap = get_nodemap(ctdb, false);
3770 if (nodemap == NULL) {
3771 return 1;
3774 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3775 if (count <= 0) {
3776 fprintf(stderr, "Memory allocation error\n");
3777 return 1;
3780 pubip.pnn = pnn;
3781 pubip.addr = *addr;
3782 ctdb_req_control_release_ip(&request, &pubip);
3784 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3785 pnn_list, count, TIMEOUT(),
3786 &request, NULL, NULL);
3787 if (ret != 0) {
3788 fprintf(stderr, "Failed to release IP on nodes\n");
3789 return ret;
3792 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3793 pnn, TIMEOUT(), &pubip);
3794 if (ret != 0) {
3795 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3796 return ret;
3799 return 0;
3802 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3803 int argc, const char **argv)
3805 ctdb_sock_addr addr;
3806 uint32_t pnn;
3807 int retries = 0;
3808 int ret = 0;
3810 if (argc != 2) {
3811 usage("moveip");
3814 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3815 if (ret != 0) {
3816 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3817 return 1;
3820 pnn = smb_strtoul(argv[1], NULL, 10, &ret, SMB_STR_STANDARD);
3821 if (pnn == CTDB_UNKNOWN_PNN || ret != 0) {
3822 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3823 return 1;
3826 while (retries < 5) {
3827 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3828 if (ret == 0) {
3829 break;
3832 sleep(3);
3833 retries++;
3836 if (ret != 0) {
3837 fprintf(stderr, "Failed to move IP %s to node %u\n",
3838 argv[0], pnn);
3839 return ret;
3842 return 0;
3845 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3846 uint32_t pnn)
3848 int ret;
3850 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3851 CTDB_BROADCAST_CONNECTED, pnn);
3852 if (ret != 0) {
3853 fprintf(stderr,
3854 "Failed to ask recovery master to distribute IPs\n");
3855 return ret;
3858 return 0;
3861 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3862 int argc, const char **argv)
3864 ctdb_sock_addr addr;
3865 struct ctdb_public_ip_list *pubip_list;
3866 struct ctdb_addr_info addr_info;
3867 unsigned int mask, i;
3868 int ret, retries = 0;
3870 if (argc != 2) {
3871 usage("addip");
3874 ret = ctdb_sock_addr_mask_from_string(argv[0], &addr, &mask);
3875 if (ret != 0) {
3876 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3877 return 1;
3880 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3881 ctdb->cmd_pnn, TIMEOUT(),
3882 false, &pubip_list);
3883 if (ret != 0) {
3884 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3885 ctdb->cmd_pnn);
3886 return 1;
3889 for (i=0; i<pubip_list->num; i++) {
3890 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3891 fprintf(stderr, "Node already knows about IP %s\n",
3892 ctdb_sock_addr_to_string(mem_ctx,
3893 &addr, false));
3894 return 0;
3898 addr_info.addr = addr;
3899 addr_info.mask = mask;
3900 addr_info.iface = argv[1];
3902 while (retries < 5) {
3903 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3904 ctdb->cmd_pnn, TIMEOUT(),
3905 &addr_info);
3906 if (ret == 0) {
3907 break;
3910 sleep(3);
3911 retries++;
3914 if (ret != 0) {
3915 fprintf(stderr, "Failed to add public IP to node %u."
3916 " Giving up\n", ctdb->cmd_pnn);
3917 return ret;
3920 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3921 if (ret != 0) {
3922 return ret;
3925 return 0;
3928 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3929 int argc, const char **argv)
3931 ctdb_sock_addr addr;
3932 struct ctdb_public_ip_list *pubip_list;
3933 struct ctdb_addr_info addr_info;
3934 unsigned int i;
3935 int ret;
3937 if (argc != 1) {
3938 usage("delip");
3941 ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
3942 if (ret != 0) {
3943 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3944 return 1;
3947 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3948 ctdb->cmd_pnn, TIMEOUT(),
3949 false, &pubip_list);
3950 if (ret != 0) {
3951 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3952 ctdb->cmd_pnn);
3953 return 1;
3956 for (i=0; i<pubip_list->num; i++) {
3957 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3958 break;
3962 if (i == pubip_list->num) {
3963 fprintf(stderr, "Node does not know about IP address %s\n",
3964 ctdb_sock_addr_to_string(mem_ctx, &addr, false));
3965 return 0;
3968 addr_info.addr = addr;
3969 addr_info.mask = 0;
3970 addr_info.iface = NULL;
3972 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3973 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
3974 if (ret != 0) {
3975 fprintf(stderr, "Failed to delete public IP from node %u\n",
3976 ctdb->cmd_pnn);
3977 return ret;
3980 return 0;
3983 #define DB_VERSION 3
3984 #define MAX_DB_NAME 64
3985 #define MAX_REC_BUFFER_SIZE (100*1000)
3987 struct db_header {
3988 unsigned long version;
3989 time_t timestamp;
3990 unsigned long flags;
3991 unsigned long nbuf;
3992 unsigned long nrec;
3993 char name[MAX_DB_NAME];
3996 struct backup_state {
3997 TALLOC_CTX *mem_ctx;
3998 struct ctdb_rec_buffer *recbuf;
3999 uint32_t db_id;
4000 int fd;
4001 unsigned int nbuf, nrec;
4004 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4005 TDB_DATA key, TDB_DATA data, void *private_data)
4007 struct backup_state *state = (struct backup_state *)private_data;
4008 size_t len;
4009 int ret;
4011 if (state->recbuf == NULL) {
4012 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4013 state->db_id);
4014 if (state->recbuf == NULL) {
4015 return ENOMEM;
4019 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4020 header, key, data);
4021 if (ret != 0) {
4022 return ret;
4025 len = ctdb_rec_buffer_len(state->recbuf);
4026 if (len < MAX_REC_BUFFER_SIZE) {
4027 return 0;
4030 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4031 if (ret != 0) {
4032 fprintf(stderr, "Failed to write records to backup file\n");
4033 return ret;
4036 state->nbuf += 1;
4037 state->nrec += state->recbuf->count;
4038 TALLOC_FREE(state->recbuf);
4040 return 0;
4043 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4044 int argc, const char **argv)
4046 const char *db_name;
4047 struct ctdb_db_context *db;
4048 uint32_t db_id;
4049 uint8_t db_flags;
4050 struct backup_state state;
4051 struct db_header db_hdr;
4052 int fd, ret;
4054 if (argc != 2) {
4055 usage("backupdb");
4058 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4059 return 1;
4062 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4063 db_flags, &db);
4064 if (ret != 0) {
4065 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4066 return ret;
4069 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4070 if (fd == -1) {
4071 ret = errno;
4072 fprintf(stderr, "Failed to open file %s for writing\n",
4073 argv[1]);
4074 return ret;
4077 /* Write empty header first */
4078 ZERO_STRUCT(db_hdr);
4079 ret = write(fd, &db_hdr, sizeof(struct db_header));
4080 if (ret == -1) {
4081 ret = errno;
4082 close(fd);
4083 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4084 return ret;
4087 state.mem_ctx = mem_ctx;
4088 state.recbuf = NULL;
4089 state.fd = fd;
4090 state.nbuf = 0;
4091 state.nrec = 0;
4093 ret = ctdb_db_traverse_local(db, true, false, backup_handler, &state);
4094 if (ret != 0) {
4095 fprintf(stderr, "Failed to collect records from DB %s\n",
4096 db_name);
4097 close(fd);
4098 return ret;
4101 if (state.recbuf != NULL) {
4102 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4103 if (ret != 0) {
4104 fprintf(stderr,
4105 "Failed to write records to backup file\n");
4106 close(fd);
4107 return ret;
4110 state.nbuf += 1;
4111 state.nrec += state.recbuf->count;
4112 TALLOC_FREE(state.recbuf);
4115 db_hdr.version = DB_VERSION;
4116 db_hdr.timestamp = time(NULL);
4117 db_hdr.flags = db_flags;
4118 db_hdr.nbuf = state.nbuf;
4119 db_hdr.nrec = state.nrec;
4120 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4122 lseek(fd, 0, SEEK_SET);
4123 ret = write(fd, &db_hdr, sizeof(struct db_header));
4124 if (ret == -1) {
4125 ret = errno;
4126 close(fd);
4127 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4128 return ret;
4131 close(fd);
4132 printf("Database backed up to %s\n", argv[1]);
4133 return 0;
4136 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4137 int argc, const char **argv)
4139 const char *db_name = NULL;
4140 struct ctdb_db_context *db;
4141 struct db_header db_hdr;
4142 struct ctdb_node_map *nodemap;
4143 struct ctdb_req_control request;
4144 struct ctdb_reply_control **reply;
4145 struct ctdb_transdb wipedb;
4146 struct ctdb_pulldb_ext pulldb;
4147 struct ctdb_rec_buffer *recbuf;
4148 uint32_t generation;
4149 uint32_t *pnn_list;
4150 char timebuf[128];
4151 ssize_t n;
4152 int fd;
4153 unsigned long i, count;
4154 int ret;
4155 uint8_t db_flags;
4157 if (argc < 1 || argc > 2) {
4158 usage("restoredb");
4161 fd = open(argv[0], O_RDONLY, 0600);
4162 if (fd == -1) {
4163 ret = errno;
4164 fprintf(stderr, "Failed to open file %s for reading\n",
4165 argv[0]);
4166 return ret;
4169 if (argc == 2) {
4170 db_name = argv[1];
4173 n = read(fd, &db_hdr, sizeof(struct db_header));
4174 if (n == -1) {
4175 ret = errno;
4176 close(fd);
4177 fprintf(stderr, "Failed to read db header from file %s\n",
4178 argv[0]);
4179 return ret;
4181 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4183 if (db_hdr.version != DB_VERSION) {
4184 fprintf(stderr,
4185 "Wrong version of backup file, expected %u, got %lu\n",
4186 DB_VERSION, db_hdr.version);
4187 close(fd);
4188 return EINVAL;
4191 if (db_name == NULL) {
4192 db_name = db_hdr.name;
4195 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4196 localtime(&db_hdr.timestamp));
4197 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4199 db_flags = db_hdr.flags & 0xff;
4200 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4201 db_flags, &db);
4202 if (ret != 0) {
4203 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4204 close(fd);
4205 return ret;
4208 nodemap = get_nodemap(ctdb, false);
4209 if (nodemap == NULL) {
4210 fprintf(stderr, "Failed to get nodemap\n");
4211 close(fd);
4212 return ENOMEM;
4215 ret = get_generation(mem_ctx, ctdb, &generation);
4216 if (ret != 0) {
4217 fprintf(stderr, "Failed to get current generation\n");
4218 close(fd);
4219 return ret;
4222 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4223 &pnn_list);
4224 if (count <= 0) {
4225 close(fd);
4226 return ENOMEM;
4229 wipedb.db_id = ctdb_db_id(db);
4230 wipedb.tid = generation;
4232 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4233 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4234 ctdb->client, pnn_list, count,
4235 TIMEOUT(), &request, NULL, NULL);
4236 if (ret != 0) {
4237 goto failed;
4241 ctdb_req_control_db_transaction_start(&request, &wipedb);
4242 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4243 pnn_list, count, TIMEOUT(),
4244 &request, NULL, NULL);
4245 if (ret != 0) {
4246 goto failed;
4249 ctdb_req_control_wipe_database(&request, &wipedb);
4250 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4251 pnn_list, count, TIMEOUT(),
4252 &request, NULL, NULL);
4253 if (ret != 0) {
4254 goto failed;
4257 pulldb.db_id = ctdb_db_id(db);
4258 pulldb.lmaster = 0;
4259 pulldb.srvid = SRVID_CTDB_PUSHDB;
4261 ctdb_req_control_db_push_start(&request, &pulldb);
4262 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4263 pnn_list, count, TIMEOUT(),
4264 &request, NULL, NULL);
4265 if (ret != 0) {
4266 goto failed;
4269 for (i=0; i<db_hdr.nbuf; i++) {
4270 struct ctdb_req_message message;
4271 TDB_DATA data;
4272 size_t np;
4274 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4275 if (ret != 0) {
4276 goto failed;
4279 data.dsize = ctdb_rec_buffer_len(recbuf);
4280 data.dptr = talloc_size(mem_ctx, data.dsize);
4281 if (data.dptr == NULL) {
4282 goto failed;
4285 ctdb_rec_buffer_push(recbuf, data.dptr, &np);
4287 message.srvid = pulldb.srvid;
4288 message.data.data = data;
4290 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4291 ctdb->client,
4292 pnn_list, count,
4293 &message, NULL);
4294 if (ret != 0) {
4295 goto failed;
4298 talloc_free(recbuf);
4299 talloc_free(data.dptr);
4302 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4303 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4304 pnn_list, count, TIMEOUT(),
4305 &request, NULL, &reply);
4306 if (ret != 0) {
4307 goto failed;
4310 for (i=0; i<count; i++) {
4311 uint32_t num_records;
4313 ret = ctdb_reply_control_db_push_confirm(reply[i],
4314 &num_records);
4315 if (ret != 0) {
4316 fprintf(stderr, "Invalid response from node %u\n",
4317 pnn_list[i]);
4318 goto failed;
4321 if (num_records != db_hdr.nrec) {
4322 fprintf(stderr, "Node %u received %u of %lu records\n",
4323 pnn_list[i], num_records, db_hdr.nrec);
4324 goto failed;
4328 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4329 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4330 pnn_list, count, TIMEOUT(),
4331 &request, NULL, NULL);
4332 if (ret != 0) {
4333 goto failed;
4336 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4337 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4338 pnn_list, count, TIMEOUT(),
4339 &request, NULL, NULL);
4340 if (ret != 0) {
4341 goto failed;
4344 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4345 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4346 ctdb->client, pnn_list, count,
4347 TIMEOUT(), &request, NULL, NULL);
4348 if (ret != 0) {
4349 goto failed;
4352 printf("Database %s restored\n", db_name);
4353 close(fd);
4354 return 0;
4357 failed:
4358 close(fd);
4359 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4360 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4361 return ret;
4364 struct dumpdbbackup_state {
4365 ctdb_rec_parser_func_t parser;
4366 struct dump_record_state sub_state;
4369 static int dumpdbbackup_handler(uint32_t reqid,
4370 struct ctdb_ltdb_header *header,
4371 TDB_DATA key, TDB_DATA data,
4372 void *private_data)
4374 struct dumpdbbackup_state *state =
4375 (struct dumpdbbackup_state *)private_data;
4376 struct ctdb_ltdb_header hdr;
4377 int ret;
4379 ret = ctdb_ltdb_header_extract(&data, &hdr);
4380 if (ret != 0) {
4381 return ret;
4384 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4387 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4388 int argc, const char **argv)
4390 struct db_header db_hdr;
4391 char timebuf[128];
4392 struct dumpdbbackup_state state;
4393 ssize_t n;
4394 unsigned long i;
4395 int fd, ret;
4397 if (argc != 1) {
4398 usage("dumpbackup");
4401 fd = open(argv[0], O_RDONLY, 0600);
4402 if (fd == -1) {
4403 ret = errno;
4404 fprintf(stderr, "Failed to open file %s for reading\n",
4405 argv[0]);
4406 return ret;
4409 n = read(fd, &db_hdr, sizeof(struct db_header));
4410 if (n == -1) {
4411 ret = errno;
4412 close(fd);
4413 fprintf(stderr, "Failed to read db header from file %s\n",
4414 argv[0]);
4415 return ret;
4417 db_hdr.name[sizeof(db_hdr.name)-1] = '\0';
4419 if (db_hdr.version != DB_VERSION) {
4420 fprintf(stderr,
4421 "Wrong version of backup file, expected %u, got %lu\n",
4422 DB_VERSION, db_hdr.version);
4423 close(fd);
4424 return EINVAL;
4427 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4428 localtime(&db_hdr.timestamp));
4429 printf("Dumping database %s from backup @ %s\n",
4430 db_hdr.name, timebuf);
4432 state.parser = dump_record;
4433 state.sub_state.count = 0;
4435 for (i=0; i<db_hdr.nbuf; i++) {
4436 struct ctdb_rec_buffer *recbuf;
4438 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4439 if (ret != 0) {
4440 fprintf(stderr, "Failed to read records\n");
4441 close(fd);
4442 return ret;
4445 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4446 &state);
4447 if (ret != 0) {
4448 fprintf(stderr, "Failed to dump records\n");
4449 close(fd);
4450 return ret;
4454 close(fd);
4455 printf("Dumped %u record(s)\n", state.sub_state.count);
4456 return 0;
4459 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4460 int argc, const char **argv)
4462 const char *db_name;
4463 struct ctdb_db_context *db;
4464 uint32_t db_id;
4465 uint8_t db_flags;
4466 struct ctdb_node_map *nodemap;
4467 struct ctdb_req_control request;
4468 struct ctdb_transdb wipedb;
4469 uint32_t generation;
4470 uint32_t *pnn_list;
4471 int count, ret;
4473 if (argc != 1) {
4474 usage("wipedb");
4477 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4478 return 1;
4481 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4482 db_flags, &db);
4483 if (ret != 0) {
4484 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4485 return ret;
4488 nodemap = get_nodemap(ctdb, false);
4489 if (nodemap == NULL) {
4490 fprintf(stderr, "Failed to get nodemap\n");
4491 return ENOMEM;
4494 ret = get_generation(mem_ctx, ctdb, &generation);
4495 if (ret != 0) {
4496 fprintf(stderr, "Failed to get current generation\n");
4497 return ret;
4500 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4501 &pnn_list);
4502 if (count <= 0) {
4503 return ENOMEM;
4506 ctdb_req_control_db_freeze(&request, db_id);
4507 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4508 ctdb->client, pnn_list, count,
4509 TIMEOUT(), &request, NULL, NULL);
4510 if (ret != 0) {
4511 goto failed;
4514 wipedb.db_id = db_id;
4515 wipedb.tid = generation;
4517 ctdb_req_control_db_transaction_start(&request, &wipedb);
4518 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4519 pnn_list, count, TIMEOUT(),
4520 &request, NULL, NULL);
4521 if (ret != 0) {
4522 goto failed;
4525 ctdb_req_control_wipe_database(&request, &wipedb);
4526 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4527 pnn_list, count, TIMEOUT(),
4528 &request, NULL, NULL);
4529 if (ret != 0) {
4530 goto failed;
4533 ctdb_req_control_db_set_healthy(&request, db_id);
4534 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4535 pnn_list, count, TIMEOUT(),
4536 &request, NULL, NULL);
4537 if (ret != 0) {
4538 goto failed;
4541 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4542 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4543 pnn_list, count, TIMEOUT(),
4544 &request, NULL, NULL);
4545 if (ret != 0) {
4546 goto failed;
4549 ctdb_req_control_db_thaw(&request, db_id);
4550 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4551 ctdb->client, pnn_list, count,
4552 TIMEOUT(), &request, NULL, NULL);
4553 if (ret != 0) {
4554 goto failed;
4557 printf("Database %s wiped\n", db_name);
4558 return 0;
4561 failed:
4562 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4563 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4564 return ret;
4567 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4568 int argc, const char **argv)
4570 uint32_t recmaster;
4571 int ret;
4573 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4574 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4575 if (ret != 0) {
4576 return ret;
4579 printf("%u\n", recmaster);
4580 return 0;
4583 static int control_event(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4584 int argc, const char **argv)
4586 char *t, *event_helper = NULL;
4588 t = getenv("CTDB_EVENT_HELPER");
4589 if (t != NULL) {
4590 event_helper = talloc_strdup(mem_ctx, t);
4591 } else {
4592 event_helper = talloc_asprintf(mem_ctx, "%s/ctdb-event",
4593 CTDB_HELPER_BINDIR);
4596 if (event_helper == NULL) {
4597 fprintf(stderr, "Unable to set event daemon helper\n");
4598 return 1;
4601 return run_helper(mem_ctx, "event daemon helper", event_helper,
4602 argc, argv);
4605 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4606 int argc, const char **argv)
4608 const char *new_argv[4];
4610 if (argc > 1) {
4611 usage("scriptstatus");
4614 new_argv[0] = "status";
4615 new_argv[1] = "legacy";
4616 new_argv[2] = (argc == 0) ? "monitor" : argv[0];
4617 new_argv[3] = NULL;
4619 (void) control_event(mem_ctx, ctdb, 3, new_argv);
4620 return 0;
4623 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4624 int argc, const char **argv)
4626 char *t, *natgw_helper = NULL;
4628 if (argc != 1) {
4629 usage("natgw");
4632 t = getenv("CTDB_NATGW_HELPER");
4633 if (t != NULL) {
4634 natgw_helper = talloc_strdup(mem_ctx, t);
4635 } else {
4636 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4637 CTDB_HELPER_BINDIR);
4640 if (natgw_helper == NULL) {
4641 fprintf(stderr, "Unable to set NAT gateway helper\n");
4642 return 1;
4645 return run_helper(mem_ctx, "NAT gateway helper", natgw_helper,
4646 argc, argv);
4650 * Find the PNN of the current node
4651 * discover the pnn by loading the nodes file and try to bind
4652 * to all addresses one at a time until the ip address is found.
4654 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4656 struct ctdb_node_map *nodemap;
4657 unsigned int i;
4659 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4660 if (nodemap == NULL) {
4661 return false;
4664 for (i=0; i<nodemap->num; i++) {
4665 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4666 continue;
4668 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4669 if (pnn != NULL) {
4670 *pnn = nodemap->node[i].pnn;
4672 talloc_free(nodemap);
4673 return true;
4677 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4678 talloc_free(nodemap);
4679 return false;
4682 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4683 int argc, const char **argv)
4685 const char *reclock;
4686 int ret;
4688 if (argc != 0) {
4689 usage("getreclock");
4692 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4693 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4694 if (ret != 0) {
4695 return ret;
4698 if (reclock != NULL) {
4699 printf("%s\n", reclock);
4702 return 0;
4705 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4706 struct ctdb_context *ctdb,
4707 int argc, const char **argv)
4709 uint32_t lmasterrole = 0;
4710 int ret;
4712 if (argc != 1) {
4713 usage("setlmasterrole");
4716 if (strcmp(argv[0], "on") == 0) {
4717 lmasterrole = 1;
4718 } else if (strcmp(argv[0], "off") == 0) {
4719 lmasterrole = 0;
4720 } else {
4721 usage("setlmasterrole");
4724 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4725 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
4726 if (ret != 0) {
4727 return ret;
4730 return 0;
4733 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
4734 struct ctdb_context *ctdb,
4735 int argc, const char **argv)
4737 uint32_t recmasterrole = 0;
4738 int ret;
4740 if (argc != 1) {
4741 usage("setrecmasterrole");
4744 if (strcmp(argv[0], "on") == 0) {
4745 recmasterrole = 1;
4746 } else if (strcmp(argv[0], "off") == 0) {
4747 recmasterrole = 0;
4748 } else {
4749 usage("setrecmasterrole");
4752 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4753 ctdb->cmd_pnn, TIMEOUT(),
4754 recmasterrole);
4755 if (ret != 0) {
4756 return ret;
4759 return 0;
4762 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
4763 struct ctdb_context *ctdb,
4764 int argc, const char **argv)
4766 uint32_t db_id;
4767 uint8_t db_flags;
4768 int ret;
4770 if (argc != 1) {
4771 usage("setdbreadonly");
4774 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4775 return 1;
4778 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4779 fprintf(stderr, "READONLY can be set only on volatile DB\n");
4780 return 1;
4783 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
4784 ctdb->cmd_pnn, TIMEOUT(), db_id);
4785 if (ret != 0) {
4786 return ret;
4789 return 0;
4792 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4793 int argc, const char **argv)
4795 uint32_t db_id;
4796 uint8_t db_flags;
4797 int ret;
4799 if (argc != 1) {
4800 usage("setdbsticky");
4803 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
4804 return 1;
4807 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
4808 fprintf(stderr, "STICKY can be set only on volatile DB\n");
4809 return 1;
4812 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
4813 ctdb->cmd_pnn, TIMEOUT(), db_id);
4814 if (ret != 0) {
4815 return ret;
4818 return 0;
4821 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4822 int argc, const char **argv)
4824 const char *db_name;
4825 struct ctdb_db_context *db;
4826 struct ctdb_transaction_handle *h;
4827 uint8_t db_flags;
4828 TDB_DATA key, data;
4829 int ret;
4831 if (argc != 2) {
4832 usage("pfetch");
4835 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4836 return 1;
4839 if (! (db_flags &
4840 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4841 fprintf(stderr, "Transactions not supported on DB %s\n",
4842 db_name);
4843 return 1;
4846 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4847 db_flags, &db);
4848 if (ret != 0) {
4849 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4850 return ret;
4853 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4854 if (ret != 0) {
4855 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4856 return ret;
4859 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4860 TIMEOUT(), db, true, &h);
4861 if (ret != 0) {
4862 fprintf(stderr, "Failed to start transaction on db %s\n",
4863 db_name);
4864 return ret;
4867 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
4868 if (ret != 0) {
4869 fprintf(stderr, "Failed to read record for key %s\n",
4870 argv[1]);
4871 ctdb_transaction_cancel(h);
4872 return ret;
4875 printf("%.*s\n", (int)data.dsize, data.dptr);
4877 ctdb_transaction_cancel(h);
4878 return 0;
4881 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4882 int argc, const char **argv)
4884 const char *db_name;
4885 struct ctdb_db_context *db;
4886 struct ctdb_transaction_handle *h;
4887 uint8_t db_flags;
4888 TDB_DATA key, data;
4889 int ret;
4891 if (argc != 3) {
4892 usage("pstore");
4895 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4896 return 1;
4899 if (! (db_flags &
4900 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4901 fprintf(stderr, "Transactions not supported on DB %s\n",
4902 db_name);
4903 return 1;
4906 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4907 db_flags, &db);
4908 if (ret != 0) {
4909 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4910 return ret;
4913 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4914 if (ret != 0) {
4915 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4916 return ret;
4919 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
4920 if (ret != 0) {
4921 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
4922 return ret;
4925 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4926 TIMEOUT(), db, false, &h);
4927 if (ret != 0) {
4928 fprintf(stderr, "Failed to start transaction on db %s\n",
4929 db_name);
4930 return ret;
4933 ret = ctdb_transaction_store_record(h, key, data);
4934 if (ret != 0) {
4935 fprintf(stderr, "Failed to store record for key %s\n",
4936 argv[1]);
4937 ctdb_transaction_cancel(h);
4938 return ret;
4941 ret = ctdb_transaction_commit(h);
4942 if (ret != 0) {
4943 fprintf(stderr, "Failed to commit transaction on db %s\n",
4944 db_name);
4945 ctdb_transaction_cancel(h);
4946 return ret;
4949 return 0;
4952 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4953 int argc, const char **argv)
4955 const char *db_name;
4956 struct ctdb_db_context *db;
4957 struct ctdb_transaction_handle *h;
4958 uint8_t db_flags;
4959 TDB_DATA key;
4960 int ret;
4962 if (argc != 2) {
4963 usage("pdelete");
4966 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
4967 return 1;
4970 if (! (db_flags &
4971 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
4972 fprintf(stderr, "Transactions not supported on DB %s\n",
4973 db_name);
4974 return 1;
4977 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4978 db_flags, &db);
4979 if (ret != 0) {
4980 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4981 return ret;
4984 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
4985 if (ret != 0) {
4986 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
4987 return ret;
4990 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
4991 TIMEOUT(), db, false, &h);
4992 if (ret != 0) {
4993 fprintf(stderr, "Failed to start transaction on db %s\n",
4994 db_name);
4995 return ret;
4998 ret = ctdb_transaction_delete_record(h, key);
4999 if (ret != 0) {
5000 fprintf(stderr, "Failed to delete record for key %s\n",
5001 argv[1]);
5002 ctdb_transaction_cancel(h);
5003 return ret;
5006 ret = ctdb_transaction_commit(h);
5007 if (ret != 0) {
5008 fprintf(stderr, "Failed to commit transaction on db %s\n",
5009 db_name);
5010 ctdb_transaction_cancel(h);
5011 return ret;
5014 return 0;
5017 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5019 const char *t;
5020 size_t n;
5021 int ret;
5023 *data = tdb_null;
5025 /* Skip whitespace */
5026 n = strspn(*ptr, " \t");
5027 t = *ptr + n;
5029 if (t[0] == '"') {
5030 /* Quoted ASCII string - no wide characters! */
5031 t++;
5032 n = strcspn(t, "\"");
5033 if (t[n] == '"') {
5034 if (n > 0) {
5035 ret = str_to_data(t, n, mem_ctx, data);
5036 if (ret != 0) {
5037 return ret;
5040 *ptr = t + n + 1;
5041 } else {
5042 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5043 return 1;
5045 } else {
5046 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5047 return 1;
5050 return 0;
5053 #define MAX_LINE_SIZE 1024
5055 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5056 TDB_DATA *key, TDB_DATA *value)
5058 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5059 const char *ptr;
5060 int ret;
5062 ptr = fgets(line, MAX_LINE_SIZE, file);
5063 if (ptr == NULL) {
5064 return false;
5067 /* Get key */
5068 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5069 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5070 /* Line Ignored but not EOF */
5071 *key = tdb_null;
5072 return true;
5075 /* Get value */
5076 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5077 if (ret != 0) {
5078 /* Line Ignored but not EOF */
5079 talloc_free(key->dptr);
5080 *key = tdb_null;
5081 return true;
5084 return true;
5087 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5088 int argc, const char **argv)
5090 const char *db_name;
5091 struct ctdb_db_context *db;
5092 struct ctdb_transaction_handle *h;
5093 uint8_t db_flags;
5094 FILE *file;
5095 TDB_DATA key = tdb_null, value = tdb_null;
5096 int ret;
5098 if (argc < 1 || argc > 2) {
5099 usage("ptrans");
5102 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5103 return 1;
5106 if (! (db_flags &
5107 (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED))) {
5108 fprintf(stderr, "Transactions not supported on DB %s\n",
5109 db_name);
5110 return 1;
5113 if (argc == 2) {
5114 file = fopen(argv[1], "r");
5115 if (file == NULL) {
5116 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5117 return 1;
5119 } else {
5120 file = stdin;
5123 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5124 db_flags, &db);
5125 if (ret != 0) {
5126 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5127 goto done;
5130 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5131 TIMEOUT(), db, false, &h);
5132 if (ret != 0) {
5133 fprintf(stderr, "Failed to start transaction on db %s\n",
5134 db_name);
5135 goto done;
5138 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5139 if (key.dsize != 0) {
5140 ret = ctdb_transaction_store_record(h, key, value);
5141 if (ret != 0) {
5142 fprintf(stderr, "Failed to store record\n");
5143 ctdb_transaction_cancel(h);
5144 goto done;
5146 talloc_free(key.dptr);
5147 talloc_free(value.dptr);
5151 ret = ctdb_transaction_commit(h);
5152 if (ret != 0) {
5153 fprintf(stderr, "Failed to commit transaction on db %s\n",
5154 db_name);
5155 ctdb_transaction_cancel(h);
5158 done:
5159 if (file != stdin) {
5160 fclose(file);
5162 return ret;
5165 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5166 int argc, const char **argv)
5168 struct tdb_context *tdb;
5169 TDB_DATA key, data;
5170 struct ctdb_ltdb_header header;
5171 int ret;
5173 if (argc < 2 || argc > 3) {
5174 usage("tfetch");
5177 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5178 if (tdb == NULL) {
5179 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5180 return 1;
5183 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5184 if (ret != 0) {
5185 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5186 tdb_close(tdb);
5187 return ret;
5190 data = tdb_fetch(tdb, key);
5191 if (data.dptr == NULL) {
5192 fprintf(stderr, "No record for key %s\n", argv[1]);
5193 tdb_close(tdb);
5194 return 1;
5197 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5198 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5199 tdb_close(tdb);
5200 return 1;
5203 tdb_close(tdb);
5205 if (argc == 3) {
5206 int fd;
5207 ssize_t nwritten;
5209 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5210 if (fd == -1) {
5211 fprintf(stderr, "Failed to open output file %s\n",
5212 argv[2]);
5213 goto fail;
5216 nwritten = sys_write(fd, data.dptr, data.dsize);
5217 if (nwritten == -1 ||
5218 (size_t)nwritten != data.dsize) {
5219 fprintf(stderr, "Failed to write record to file\n");
5220 close(fd);
5221 goto fail;
5224 close(fd);
5227 fail:
5228 ret = ctdb_ltdb_header_extract(&data, &header);
5229 if (ret != 0) {
5230 fprintf(stderr, "Failed to parse header from data\n");
5231 return 1;
5234 dump_ltdb_header(&header);
5235 dump_tdb_data("data", data);
5237 return 0;
5240 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5241 int argc, const char **argv)
5243 struct tdb_context *tdb;
5244 TDB_DATA key, data[2], value;
5245 struct ctdb_ltdb_header header;
5246 uint8_t header_buf[sizeof(struct ctdb_ltdb_header)];
5247 size_t np;
5248 int ret = 0;
5250 if (argc < 3 || argc > 5) {
5251 usage("tstore");
5254 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5255 if (tdb == NULL) {
5256 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5257 return 1;
5260 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5261 if (ret != 0) {
5262 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5263 tdb_close(tdb);
5264 return ret;
5267 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5268 if (ret != 0) {
5269 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5270 tdb_close(tdb);
5271 return ret;
5274 ZERO_STRUCT(header);
5276 if (argc > 3) {
5277 header.rsn = (uint64_t)smb_strtoull(argv[3],
5278 NULL,
5280 &ret,
5281 SMB_STR_STANDARD);
5282 if (ret != 0) {
5283 return ret;
5286 if (argc > 4) {
5287 header.dmaster = (uint32_t)atol(argv[4]);
5289 if (argc > 5) {
5290 header.flags = (uint32_t)atol(argv[5]);
5293 ctdb_ltdb_header_push(&header, header_buf, &np);
5295 data[0].dsize = np;
5296 data[0].dptr = header_buf;
5298 data[1].dsize = value.dsize;
5299 data[1].dptr = value.dptr;
5301 ret = tdb_storev(tdb, key, data, 2, TDB_REPLACE);
5302 if (ret != 0) {
5303 fprintf(stderr, "Failed to write record %s to file %s\n",
5304 argv[1], argv[0]);
5307 tdb_close(tdb);
5309 return ret;
5312 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5313 int argc, const char **argv)
5315 const char *db_name;
5316 struct ctdb_db_context *db;
5317 struct ctdb_record_handle *h;
5318 uint8_t db_flags;
5319 TDB_DATA key, data;
5320 bool readonly = false;
5321 int ret;
5323 if (argc < 2 || argc > 3) {
5324 usage("readkey");
5327 if (argc == 3) {
5328 if (strcmp(argv[2], "readonly") == 0) {
5329 readonly = true;
5330 } else {
5331 usage("readkey");
5335 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5336 return 1;
5339 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5340 fprintf(stderr, "DB %s is not a volatile database\n",
5341 db_name);
5342 return 1;
5345 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5346 db_flags, &db);
5347 if (ret != 0) {
5348 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5349 return ret;
5352 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5353 if (ret != 0) {
5354 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5355 return ret;
5358 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5359 db, key, readonly, &h, NULL, &data);
5360 if (ret != 0) {
5361 fprintf(stderr, "Failed to read record for key %s\n",
5362 argv[1]);
5363 } else {
5364 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5365 (int)data.dsize, data.dptr);
5368 talloc_free(h);
5369 return ret;
5372 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5373 int argc, const char **argv)
5375 const char *db_name;
5376 struct ctdb_db_context *db;
5377 struct ctdb_record_handle *h;
5378 uint8_t db_flags;
5379 TDB_DATA key, data;
5380 int ret;
5382 if (argc != 3) {
5383 usage("writekey");
5386 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5387 return 1;
5390 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5391 fprintf(stderr, "DB %s is not a volatile database\n",
5392 db_name);
5393 return 1;
5396 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5397 db_flags, &db);
5398 if (ret != 0) {
5399 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5400 return ret;
5403 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5404 if (ret != 0) {
5405 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5406 return ret;
5409 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5410 if (ret != 0) {
5411 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5412 return ret;
5415 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5416 db, key, false, &h, NULL, NULL);
5417 if (ret != 0) {
5418 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5419 return ret;
5422 ret = ctdb_store_record(h, data);
5423 if (ret != 0) {
5424 fprintf(stderr, "Failed to store record for key %s\n",
5425 argv[1]);
5428 talloc_free(h);
5429 return ret;
5432 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5433 int argc, const char **argv)
5435 const char *db_name;
5436 struct ctdb_db_context *db;
5437 struct ctdb_record_handle *h;
5438 uint8_t db_flags;
5439 TDB_DATA key, data;
5440 int ret;
5442 if (argc != 2) {
5443 usage("deletekey");
5446 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5447 return 1;
5450 if (db_flags & (CTDB_DB_FLAGS_PERSISTENT | CTDB_DB_FLAGS_REPLICATED)) {
5451 fprintf(stderr, "DB %s is not a volatile database\n",
5452 db_name);
5453 return 1;
5456 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5457 db_flags, &db);
5458 if (ret != 0) {
5459 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5460 return ret;
5463 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5464 if (ret != 0) {
5465 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5466 return ret;
5469 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5470 db, key, false, &h, NULL, &data);
5471 if (ret != 0) {
5472 fprintf(stderr, "Failed to fetch record for key %s\n",
5473 argv[1]);
5474 return ret;
5477 ret = ctdb_delete_record(h);
5478 if (ret != 0) {
5479 fprintf(stderr, "Failed to delete record for key %s\n",
5480 argv[1]);
5483 talloc_free(h);
5484 return ret;
5487 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5488 int argc, const char **argv)
5490 struct sockaddr_in sin;
5491 unsigned int port;
5492 int s, v;
5493 int ret;
5495 if (argc != 1) {
5496 usage("chktcpport");
5499 port = atoi(argv[0]);
5501 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5502 if (s == -1) {
5503 fprintf(stderr, "Failed to open local socket\n");
5504 return errno;
5507 v = fcntl(s, F_GETFL, 0);
5508 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5509 fprintf(stderr, "Unable to set socket non-blocking\n");
5510 close(s);
5511 return errno;
5514 bzero(&sin, sizeof(sin));
5515 sin.sin_family = AF_INET;
5516 sin.sin_port = htons(port);
5517 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5518 close(s);
5519 if (ret == -1) {
5520 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5521 return errno;
5524 return 0;
5527 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5528 int argc, const char **argv)
5530 uint32_t db_id;
5531 const char *db_name;
5532 uint64_t seqnum;
5533 int ret;
5535 if (argc != 1) {
5536 usage("getdbseqnum");
5539 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5540 return 1;
5543 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5544 ctdb->cmd_pnn, TIMEOUT(), db_id,
5545 &seqnum);
5546 if (ret != 0) {
5547 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5548 db_name);
5549 return ret;
5552 printf("0x%"PRIx64"\n", seqnum);
5553 return 0;
5556 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5557 int argc, const char **argv)
5559 const char *nodestring = NULL;
5560 struct ctdb_node_map *nodemap;
5561 unsigned int i;
5562 int ret;
5563 bool print_hdr = false;
5565 if (argc > 1) {
5566 usage("nodestatus");
5569 if (argc == 1) {
5570 nodestring = argv[0];
5571 if (strcmp(nodestring, "all") == 0) {
5572 print_hdr = true;
5576 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5577 return 1;
5580 if (options.machinereadable) {
5581 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5582 } else {
5583 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, print_hdr);
5586 ret = 0;
5587 for (i=0; i<nodemap->num; i++) {
5588 uint32_t flags = nodemap->node[i].flags;
5590 if ((flags & NODE_FLAGS_DELETED) != 0) {
5591 continue;
5594 ret |= flags;
5597 return ret;
5600 const struct {
5601 const char *name;
5602 uint32_t offset;
5603 } db_stats_fields[] = {
5604 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5605 DBSTATISTICS_FIELD(db_ro_delegations),
5606 DBSTATISTICS_FIELD(db_ro_revokes),
5607 DBSTATISTICS_FIELD(locks.num_calls),
5608 DBSTATISTICS_FIELD(locks.num_current),
5609 DBSTATISTICS_FIELD(locks.num_pending),
5610 DBSTATISTICS_FIELD(locks.num_failed),
5613 static void print_dbstatistics(const char *db_name,
5614 struct ctdb_db_statistics *s)
5616 size_t i;
5617 const char *prefix = NULL;
5618 int preflen = 0;
5620 printf("DB Statistics %s\n", db_name);
5622 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5623 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5624 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5625 if (! prefix ||
5626 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5627 prefix = db_stats_fields[i].name;
5628 printf(" %*.*s\n", preflen-1, preflen-1,
5629 db_stats_fields[i].name);
5631 } else {
5632 preflen = 0;
5634 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5635 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5636 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5639 printf(" hop_count_buckets:");
5640 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5641 printf(" %d", s->hop_count_bucket[i]);
5643 printf("\n");
5645 printf(" lock_buckets:");
5646 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5647 printf(" %d", s->locks.buckets[i]);
5649 printf("\n");
5651 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5652 "locks_latency MIN/AVG/MAX",
5653 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5654 s->locks.latency.max, s->locks.latency.num);
5656 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5657 "vacuum_latency MIN/AVG/MAX",
5658 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5659 s->vacuum.latency.max, s->vacuum.latency.num);
5661 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5662 for (i=0; i<s->num_hot_keys; i++) {
5663 size_t j;
5664 printf(" Count:%d Key:", s->hot_keys[i].count);
5665 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5666 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5668 printf("\n");
5672 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5673 int argc, const char **argv)
5675 uint32_t db_id;
5676 const char *db_name;
5677 struct ctdb_db_statistics *dbstats;
5678 int ret;
5680 if (argc != 1) {
5681 usage("dbstatistics");
5684 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5685 return 1;
5688 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5689 ctdb->cmd_pnn, TIMEOUT(), db_id,
5690 &dbstats);
5691 if (ret != 0) {
5692 fprintf(stderr, "Failed to get statistics for DB %s\n",
5693 db_name);
5694 return ret;
5697 print_dbstatistics(db_name, dbstats);
5698 return 0;
5701 struct disable_takeover_runs_state {
5702 uint32_t *pnn_list;
5703 unsigned int node_count;
5704 bool *reply;
5705 int status;
5706 bool done;
5709 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5710 void *private_data)
5712 struct disable_takeover_runs_state *state =
5713 (struct disable_takeover_runs_state *)private_data;
5714 unsigned int i;
5715 int ret;
5717 if (data.dsize != sizeof(int)) {
5718 /* Ignore packet */
5719 return;
5722 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5723 ret = *(int *)data.dptr;
5724 if (ret < 0) {
5725 state->status = ret;
5726 state->done = true;
5727 return;
5729 for (i=0; i<state->node_count; i++) {
5730 if (state->pnn_list[i] == (uint32_t)ret) {
5731 state->reply[i] = true;
5732 break;
5736 state->done = true;
5737 for (i=0; i<state->node_count; i++) {
5738 if (! state->reply[i]) {
5739 state->done = false;
5740 break;
5745 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
5746 struct ctdb_context *ctdb, uint32_t timeout,
5747 uint32_t *pnn_list, int count)
5749 struct ctdb_disable_message disable = { 0 };
5750 struct disable_takeover_runs_state state;
5751 int ret, i;
5753 disable.pnn = ctdb->pnn;
5754 disable.srvid = next_srvid(ctdb);
5755 disable.timeout = timeout;
5757 state.pnn_list = pnn_list;
5758 state.node_count = count;
5759 state.done = false;
5760 state.status = 0;
5761 state.reply = talloc_zero_array(mem_ctx, bool, count);
5762 if (state.reply == NULL) {
5763 return ENOMEM;
5766 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
5767 disable.srvid,
5768 disable_takeover_run_handler,
5769 &state);
5770 if (ret != 0) {
5771 return ret;
5774 for (i=0; i<count; i++) {
5775 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
5776 ctdb->client,
5777 pnn_list[i],
5778 &disable);
5779 if (ret != 0) {
5780 goto fail;
5784 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
5785 if (ret == ETIME) {
5786 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
5787 } else {
5788 ret = (state.status >= 0 ? 0 : 1);
5791 fail:
5792 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
5793 disable.srvid, &state);
5794 return ret;
5797 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5798 int argc, const char **argv)
5800 const char *nodestring = NULL;
5801 struct ctdb_node_map *nodemap, *nodemap2;
5802 struct ctdb_req_control request;
5803 uint32_t *pnn_list, *pnn_list2;
5804 int ret, count, count2;
5806 if (argc > 1) {
5807 usage("reloadips");
5810 if (argc == 1) {
5811 nodestring = argv[0];
5814 nodemap = get_nodemap(ctdb, false);
5815 if (nodemap == NULL) {
5816 return 1;
5819 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
5820 return 1;
5823 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
5824 mem_ctx, &pnn_list);
5825 if (count <= 0) {
5826 fprintf(stderr, "Memory allocation error\n");
5827 return 1;
5830 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
5831 mem_ctx, &pnn_list2);
5832 if (count2 <= 0) {
5833 fprintf(stderr, "Memory allocation error\n");
5834 return 1;
5837 /* Disable takeover runs on all connected nodes. A reply
5838 * indicating success is needed from each node so all nodes
5839 * will need to be active.
5841 * A check could be added to not allow reloading of IPs when
5842 * there are disconnected nodes. However, this should
5843 * probably be left up to the administrator.
5845 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
5846 pnn_list, count);
5847 if (ret != 0) {
5848 fprintf(stderr, "Failed to disable takeover runs\n");
5849 return ret;
5852 /* Now tell all the desired nodes to reload their public IPs.
5853 * Keep trying this until it succeeds. This assumes all
5854 * failures are transient, which might not be true...
5856 ctdb_req_control_reload_public_ips(&request);
5857 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
5858 pnn_list2, count2, TIMEOUT(),
5859 &request, NULL, NULL);
5860 if (ret != 0) {
5861 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
5864 /* It isn't strictly necessary to wait until takeover runs are
5865 * re-enabled but doing so can't hurt.
5867 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
5868 if (ret != 0) {
5869 fprintf(stderr, "Failed to enable takeover runs\n");
5870 return ret;
5873 return ipreallocate(mem_ctx, ctdb);
5877 static const struct ctdb_cmd {
5878 const char *name;
5879 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
5880 bool without_daemon; /* can be run without daemon running ? */
5881 bool remote; /* can be run on remote nodes */
5882 const char *msg;
5883 const char *args;
5884 } ctdb_commands[] = {
5885 { "version", control_version, true, false,
5886 "show version of ctdb", NULL },
5887 { "status", control_status, false, true,
5888 "show node status", NULL },
5889 { "uptime", control_uptime, false, true,
5890 "show node uptime", NULL },
5891 { "ping", control_ping, false, true,
5892 "ping a node", NULL },
5893 { "runstate", control_runstate, false, true,
5894 "get/check runstate of a node",
5895 "[setup|first_recovery|startup|running]" },
5896 { "getvar", control_getvar, false, true,
5897 "get a tunable variable", "<name>" },
5898 { "setvar", control_setvar, false, true,
5899 "set a tunable variable", "<name> <value>" },
5900 { "listvars", control_listvars, false, true,
5901 "list tunable variables", NULL },
5902 { "statistics", control_statistics, false, true,
5903 "show ctdb statistics", NULL },
5904 { "statisticsreset", control_statistics_reset, false, true,
5905 "reset ctdb statistics", NULL },
5906 { "stats", control_stats, false, true,
5907 "show rolling statistics", "[count]" },
5908 { "ip", control_ip, false, true,
5909 "show public ips", "[all]" },
5910 { "ipinfo", control_ipinfo, false, true,
5911 "show public ip details", "<ip>" },
5912 { "ifaces", control_ifaces, false, true,
5913 "show interfaces", NULL },
5914 { "setifacelink", control_setifacelink, false, true,
5915 "set interface link status", "<iface> up|down" },
5916 { "process-exists", control_process_exists, false, true,
5917 "check if a process exists on a node", "<pid> [<srvid>]" },
5918 { "getdbmap", control_getdbmap, false, true,
5919 "show attached databases", NULL },
5920 { "getdbstatus", control_getdbstatus, false, true,
5921 "show database status", "<dbname|dbid>" },
5922 { "catdb", control_catdb, false, false,
5923 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5924 { "cattdb", control_cattdb, false, false,
5925 "dump local ctdb database", "<dbname|dbid>" },
5926 { "getcapabilities", control_getcapabilities, false, true,
5927 "show node capabilities", NULL },
5928 { "pnn", control_pnn, false, false,
5929 "show the pnn of the currnet node", NULL },
5930 { "lvs", control_lvs, false, false,
5931 "show lvs configuration", "leader|list|status" },
5932 { "setdebug", control_setdebug, false, true,
5933 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5934 { "getdebug", control_getdebug, false, true,
5935 "get debug level", NULL },
5936 { "attach", control_attach, false, false,
5937 "attach a database", "<dbname> [persistent|replicated]" },
5938 { "detach", control_detach, false, false,
5939 "detach database(s)", "<dbname|dbid> ..." },
5940 { "dumpmemory", control_dumpmemory, false, true,
5941 "dump ctdbd memory map", NULL },
5942 { "rddumpmemory", control_rddumpmemory, false, true,
5943 "dump recoverd memory map", NULL },
5944 { "getpid", control_getpid, false, true,
5945 "get ctdbd process ID", NULL },
5946 { "disable", control_disable, false, true,
5947 "disable a node", NULL },
5948 { "enable", control_enable, false, true,
5949 "enable a node", NULL },
5950 { "stop", control_stop, false, true,
5951 "stop a node", NULL },
5952 { "continue", control_continue, false, true,
5953 "continue a stopped node", NULL },
5954 { "ban", control_ban, false, true,
5955 "ban a node", "<bantime>"},
5956 { "unban", control_unban, false, true,
5957 "unban a node", NULL },
5958 { "shutdown", control_shutdown, false, true,
5959 "shutdown ctdb daemon", NULL },
5960 { "recover", control_recover, false, true,
5961 "force recovery", NULL },
5962 { "sync", control_ipreallocate, false, true,
5963 "run ip reallocation (deprecated)", NULL },
5964 { "ipreallocate", control_ipreallocate, false, true,
5965 "run ip reallocation", NULL },
5966 { "gratarp", control_gratarp, false, true,
5967 "send a gratuitous arp", "<ip> <interface>" },
5968 { "tickle", control_tickle, true, false,
5969 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5970 { "gettickles", control_gettickles, false, true,
5971 "get the list of tickles", "<ip> [<port>]" },
5972 { "addtickle", control_addtickle, false, true,
5973 "add a tickle", "<ip>:<port> <ip>:<port>" },
5974 { "deltickle", control_deltickle, false, true,
5975 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5976 { "listnodes", control_listnodes, true, true,
5977 "list nodes in the cluster", NULL },
5978 { "reloadnodes", control_reloadnodes, false, false,
5979 "reload the nodes file all nodes", NULL },
5980 { "moveip", control_moveip, false, false,
5981 "move an ip address to another node", "<ip> <node>" },
5982 { "addip", control_addip, false, true,
5983 "add an ip address to a node", "<ip/mask> <iface>" },
5984 { "delip", control_delip, false, true,
5985 "delete an ip address from a node", "<ip>" },
5986 { "backupdb", control_backupdb, false, false,
5987 "backup a database into a file", "<dbname|dbid> <file>" },
5988 { "restoredb", control_restoredb, false, false,
5989 "restore a database from a file", "<file> [dbname]" },
5990 { "dumpdbbackup", control_dumpdbbackup, true, false,
5991 "dump database from a backup file", "<file>" },
5992 { "wipedb", control_wipedb, false, false,
5993 "wipe the contents of a database.", "<dbname|dbid>"},
5994 { "recmaster", control_recmaster, false, true,
5995 "show the pnn for the recovery master", NULL },
5996 { "event", control_event, true, false,
5997 "event and event script commands", NULL },
5998 { "scriptstatus", control_scriptstatus, true, false,
5999 "show event script status",
6000 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6001 { "natgw", control_natgw, false, false,
6002 "show natgw configuration", "leader|list|status" },
6003 { "getreclock", control_getreclock, false, true,
6004 "get recovery lock file", NULL },
6005 { "setlmasterrole", control_setlmasterrole, false, true,
6006 "set LMASTER role", "on|off" },
6007 { "setrecmasterrole", control_setrecmasterrole, false, true,
6008 "set RECMASTER role", "on|off"},
6009 { "setdbreadonly", control_setdbreadonly, false, true,
6010 "enable readonly records", "<dbname|dbid>" },
6011 { "setdbsticky", control_setdbsticky, false, true,
6012 "enable sticky records", "<dbname|dbid>"},
6013 { "pfetch", control_pfetch, false, false,
6014 "fetch record from persistent database", "<dbname|dbid> <key>" },
6015 { "pstore", control_pstore, false, false,
6016 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6017 { "pdelete", control_pdelete, false, false,
6018 "delete record from persistent database", "<dbname|dbid> <key>" },
6019 { "ptrans", control_ptrans, false, false,
6020 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6021 { "tfetch", control_tfetch, false, true,
6022 "fetch a record", "<tdb-file> <key> [<file>]" },
6023 { "tstore", control_tstore, false, true,
6024 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6025 { "readkey", control_readkey, false, false,
6026 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6027 { "writekey", control_writekey, false, false,
6028 "write value for a database key", "<dbname|dbid> <key> <value>" },
6029 { "deletekey", control_deletekey, false, false,
6030 "delete a database key", "<dbname|dbid> <key>" },
6031 { "checktcpport", control_checktcpport, true, false,
6032 "check if a service is bound to a specific tcp port or not", "<port>" },
6033 { "getdbseqnum", control_getdbseqnum, false, false,
6034 "get database sequence number", "<dbname|dbid>" },
6035 { "nodestatus", control_nodestatus, false, true,
6036 "show and return node status", "[all|<pnn-list>]" },
6037 { "dbstatistics", control_dbstatistics, false, true,
6038 "show database statistics", "<dbname|dbid>" },
6039 { "reloadips", control_reloadips, false, false,
6040 "reload the public addresses file", "[all|<pnn-list>]" },
6043 static const struct ctdb_cmd *match_command(const char *command)
6045 const struct ctdb_cmd *cmd;
6046 size_t i;
6048 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6049 cmd = &ctdb_commands[i];
6050 if (strlen(command) == strlen(cmd->name) &&
6051 strncmp(command, cmd->name, strlen(command)) == 0) {
6052 return cmd;
6056 return NULL;
6061 * Show usage message
6063 static void usage_full(void)
6065 size_t i;
6067 poptPrintHelp(pc, stdout, 0);
6068 printf("\nCommands:\n");
6069 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6070 printf(" %-15s %-27s %s\n",
6071 ctdb_commands[i].name,
6072 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6073 ctdb_commands[i].msg);
6077 static void usage(const char *command)
6079 const struct ctdb_cmd *cmd;
6081 if (command == NULL) {
6082 usage_full();
6083 exit(1);
6086 cmd = match_command(command);
6087 if (cmd == NULL) {
6088 usage_full();
6089 } else {
6090 poptPrintUsage(pc, stdout, 0);
6091 printf("\nCommands:\n");
6092 printf(" %-15s %-27s %s\n",
6093 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6096 exit(1);
6099 struct poptOption cmdline_options[] = {
6100 POPT_AUTOHELP
6102 .longName = "debug",
6103 .shortName = 'd',
6104 .argInfo = POPT_ARG_STRING,
6105 .arg = &options.debuglevelstr,
6106 .val = 0,
6107 .descrip = "debug level",
6110 .longName = "timelimit",
6111 .shortName = 't',
6112 .argInfo = POPT_ARG_INT,
6113 .arg = &options.timelimit,
6114 .val = 0,
6115 .descrip = "timelimit (in seconds)",
6118 .longName = "node",
6119 .shortName = 'n',
6120 .argInfo = POPT_ARG_INT,
6121 .arg = &options.pnn,
6122 .val = 0,
6123 .descrip = "node specification - integer",
6126 .longName = NULL,
6127 .shortName = 'Y',
6128 .argInfo = POPT_ARG_NONE,
6129 .arg = &options.machinereadable,
6130 .val = 0,
6131 .descrip = "enable machine readable output",
6134 .longName = "separator",
6135 .shortName = 'x',
6136 .argInfo = POPT_ARG_STRING,
6137 .arg = &options.sep,
6138 .val = 0,
6139 .descrip = "specify separator for machine readable output",
6140 .argDescrip = "CHAR",
6143 .shortName = 'X',
6144 .argInfo = POPT_ARG_NONE,
6145 .arg = &options.machineparsable,
6146 .val = 0,
6147 .descrip = "enable machine parsable output with separator |",
6150 .longName = "verbose",
6151 .shortName = 'v',
6152 .argInfo = POPT_ARG_NONE,
6153 .arg = &options.verbose,
6154 .val = 0,
6155 .descrip = "enable verbose output",
6158 .longName = "maxruntime",
6159 .shortName = 'T',
6160 .argInfo = POPT_ARG_INT,
6161 .arg = &options.maxruntime,
6162 .val = 0,
6163 .descrip = "die if runtime exceeds this limit (in seconds)",
6165 POPT_TABLEEND
6168 static int process_command(const struct ctdb_cmd *cmd, int argc,
6169 const char **argv)
6171 TALLOC_CTX *tmp_ctx;
6172 struct ctdb_context *ctdb;
6173 const char *ctdb_socket;
6174 int ret;
6175 bool status;
6176 uint64_t srvid_offset;
6178 tmp_ctx = talloc_new(NULL);
6179 if (tmp_ctx == NULL) {
6180 fprintf(stderr, "Memory allocation error\n");
6181 goto fail;
6184 if (cmd->without_daemon) {
6185 if (options.pnn != -1) {
6186 fprintf(stderr,
6187 "Cannot specify node for command %s\n",
6188 cmd->name);
6189 goto fail;
6192 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6193 talloc_free(tmp_ctx);
6194 return ret;
6197 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6198 if (ctdb == NULL) {
6199 fprintf(stderr, "Memory allocation error\n");
6200 goto fail;
6203 ctdb->ev = tevent_context_init(ctdb);
6204 if (ctdb->ev == NULL) {
6205 fprintf(stderr, "Failed to initialize tevent\n");
6206 goto fail;
6209 ctdb_socket = path_socket(ctdb, "ctdbd");
6210 if (ctdb_socket == NULL) {
6211 fprintf(stderr, "Memory allocation error\n");
6212 goto fail;
6215 ret = ctdb_client_init(ctdb, ctdb->ev, ctdb_socket, &ctdb->client);
6216 if (ret != 0) {
6217 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6218 ctdb_socket);
6220 if (!find_node_xpnn(ctdb, NULL)) {
6221 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6223 goto fail;
6226 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6227 srvid_offset = getpid() & 0xFFFF;
6228 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6230 if (options.pnn != -1) {
6231 status = verify_pnn(ctdb, options.pnn);
6232 if (! status) {
6233 goto fail;
6236 ctdb->cmd_pnn = options.pnn;
6237 } else {
6238 ctdb->cmd_pnn = ctdb->pnn;
6241 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6242 fprintf(stderr, "Node cannot be specified for command %s\n",
6243 cmd->name);
6244 goto fail;
6247 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6248 talloc_free(tmp_ctx);
6249 return ret;
6251 fail:
6252 talloc_free(tmp_ctx);
6253 return 1;
6256 static void signal_handler(int sig)
6258 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6261 static void alarm_handler(int sig)
6263 /* Kill any child processes */
6264 signal(SIGTERM, signal_handler);
6265 kill(0, SIGTERM);
6267 _exit(1);
6270 int main(int argc, const char *argv[])
6272 int opt;
6273 const char **extra_argv;
6274 int extra_argc;
6275 const struct ctdb_cmd *cmd;
6276 const char *test_mode;
6277 int loglevel;
6278 bool ok;
6279 int ret = 0;
6281 setlinebuf(stdout);
6283 /* Set default options */
6284 options.debuglevelstr = NULL;
6285 options.timelimit = 10;
6286 options.sep = "|";
6287 options.maxruntime = 0;
6288 options.pnn = -1;
6290 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6291 POPT_CONTEXT_KEEP_FIRST);
6292 while ((opt = poptGetNextOpt(pc)) != -1) {
6293 fprintf(stderr, "Invalid option %s: %s\n",
6294 poptBadOption(pc, 0), poptStrerror(opt));
6295 exit(1);
6298 if (options.maxruntime == 0) {
6299 const char *ctdb_timeout;
6301 ctdb_timeout = getenv("CTDB_TIMEOUT");
6302 if (ctdb_timeout != NULL) {
6303 options.maxruntime = smb_strtoul(ctdb_timeout,
6304 NULL,
6306 &ret,
6307 SMB_STR_STANDARD);
6308 if (ret != 0) {
6309 fprintf(stderr, "Invalid value CTDB_TIMEOUT\n");
6310 exit(1);
6312 } else {
6313 options.maxruntime = 120;
6317 if (options.machineparsable) {
6318 options.machinereadable = 1;
6321 /* setup the remaining options for the commands */
6322 extra_argc = 0;
6323 extra_argv = poptGetArgs(pc);
6324 if (extra_argv) {
6325 extra_argv++;
6326 while (extra_argv[extra_argc]) extra_argc++;
6329 if (extra_argc < 1) {
6330 usage(NULL);
6333 cmd = match_command(extra_argv[0]);
6334 if (cmd == NULL) {
6335 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6336 exit(1);
6339 /* Enable logging */
6340 setup_logging("ctdb", DEBUG_STDERR);
6341 ok = debug_level_parse(options.debuglevelstr, &loglevel);
6342 if (!ok) {
6343 loglevel = DEBUG_ERR;
6345 debuglevel_set(loglevel);
6347 /* Stop process group kill in alarm_handler() from killing tests */
6348 test_mode = getenv("CTDB_TEST_MODE");
6349 if (test_mode != NULL) {
6350 const char *have_setpgid = getenv("CTDB_TOOL_SETPGID");
6351 if (have_setpgid == NULL) {
6352 setpgid(0, 0);
6353 setenv("CTDB_TOOL_SETPGID", "1", 1);
6357 signal(SIGALRM, alarm_handler);
6358 alarm(options.maxruntime);
6360 ret = process_command(cmd, extra_argc, extra_argv);
6361 if (ret == -1) {
6362 ret = 1;
6365 (void)poptFreeContext(pc);
6367 return ret;