4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
33 #include "common/version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
38 #include "common/db_hash.h"
39 #include "common/logging.h"
40 #include "protocol/protocol.h"
41 #include "protocol/protocol_api.h"
42 #include "protocol/protocol_util.h"
43 #include "common/system.h"
44 #include "client/client.h"
45 #include "client/client_sync.h"
47 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
49 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
50 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
53 const char *debuglevelstr
;
61 int printemptyrecords
;
68 static poptContext pc
;
71 struct tevent_context
*ev
;
72 struct ctdb_client_context
*client
;
73 struct ctdb_node_map
*nodemap
;
74 uint32_t pnn
, cmd_pnn
;
78 static void usage(const char *command
);
84 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
86 return (tv2
->tv_sec
- tv
->tv_sec
) +
87 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
90 static struct ctdb_node_and_flags
*get_node_by_pnn(
91 struct ctdb_node_map
*nodemap
,
96 for (i
=0; i
<nodemap
->num
; i
++) {
97 if (nodemap
->node
[i
].pnn
== pnn
) {
98 return &nodemap
->node
[i
];
104 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
106 static const struct {
110 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
111 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
112 { NODE_FLAGS_BANNED
, "BANNED" },
113 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
114 { NODE_FLAGS_DELETED
, "DELETED" },
115 { NODE_FLAGS_STOPPED
, "STOPPED" },
116 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
118 char *flags_str
= NULL
;
121 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
122 if (flags
& flag_names
[i
].flag
) {
123 if (flags_str
== NULL
) {
124 flags_str
= talloc_asprintf(mem_ctx
,
125 "%s", flag_names
[i
].name
);
127 flags_str
= talloc_asprintf_append(flags_str
,
128 "|%s", flag_names
[i
].name
);
130 if (flags_str
== NULL
) {
131 return "OUT-OF-MEMORY";
135 if (flags_str
== NULL
) {
142 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
149 * Get consistent nodemap information.
151 * If nodemap is already cached, use that. If not get it.
152 * If the current node is BANNED, then get nodemap from "better" node.
154 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
157 struct ctdb_node_map
*nodemap
;
158 struct ctdb_node_and_flags
*node
;
159 uint32_t current_node
;
163 TALLOC_FREE(ctdb
->nodemap
);
166 if (ctdb
->nodemap
!= NULL
) {
167 return ctdb
->nodemap
;
170 tmp_ctx
= talloc_new(ctdb
);
171 if (tmp_ctx
== NULL
) {
175 current_node
= ctdb
->pnn
;
177 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
178 current_node
, TIMEOUT(), &nodemap
);
180 fprintf(stderr
, "Failed to get nodemap from node %u\n",
185 node
= get_node_by_pnn(nodemap
, current_node
);
186 if (node
->flags
& NODE_FLAGS_BANNED
) {
189 current_node
= (current_node
+ 1) % nodemap
->num
;
190 node
= get_node_by_pnn(nodemap
, current_node
);
192 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
195 } while (current_node
!= ctdb
->pnn
);
197 if (current_node
== ctdb
->pnn
) {
198 /* Tried all nodes in the cluster */
199 fprintf(stderr
, "Warning: All nodes are banned.\n");
206 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
210 talloc_free(tmp_ctx
);
214 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
216 struct ctdb_node_map
*nodemap
;
224 nodemap
= get_nodemap(ctdb
, false);
225 if (nodemap
== NULL
) {
230 for (i
=0; i
<nodemap
->num
; i
++) {
231 if (nodemap
->node
[i
].pnn
== pnn
) {
237 fprintf(stderr
, "Node %u does not exist\n", pnn
);
241 if (nodemap
->node
[i
].flags
&
242 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
243 fprintf(stderr
, "Node %u has status %s\n", pnn
,
244 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
251 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
252 struct ctdb_node_map
*nodemap
)
254 struct ctdb_node_map
*nodemap2
;
256 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
257 if (nodemap2
== NULL
) {
261 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
263 if (nodemap2
->node
== NULL
) {
264 talloc_free(nodemap2
);
272 * Get the number and the list of matching nodes
274 * nodestring := NULL | all | pnn,[pnn,...]
276 * If nodestring is NULL, use the current node.
278 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
279 const char *nodestring
,
280 struct ctdb_node_map
**out
)
282 struct ctdb_node_map
*nodemap
, *nodemap2
;
283 struct ctdb_node_and_flags
*node
;
286 nodemap
= get_nodemap(ctdb
, false);
287 if (nodemap
== NULL
) {
291 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
292 if (nodemap2
== NULL
) {
296 if (nodestring
== NULL
) {
297 for (i
=0; i
<nodemap
->num
; i
++) {
298 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
299 nodemap2
->node
[0] = nodemap
->node
[i
];
308 if (strcmp(nodestring
, "all") == 0) {
309 for (i
=0; i
<nodemap
->num
; i
++) {
310 nodemap2
->node
[i
] = nodemap
->node
[i
];
312 nodemap2
->num
= nodemap
->num
;
318 ns
= talloc_strdup(mem_ctx
, nodestring
);
323 tok
= strtok(ns
, ",");
324 while (tok
!= NULL
) {
328 pnn
= (uint32_t)strtoul(tok
, &endptr
, 0);
329 if (pnn
== 0 && tok
== endptr
) {
330 fprintf(stderr
, "Invalid node %s\n", tok
);
334 node
= get_node_by_pnn(nodemap
, pnn
);
336 fprintf(stderr
, "Node %u does not exist\n",
341 nodemap2
->node
[nodemap2
->num
] = *node
;
344 tok
= strtok(NULL
, ",");
353 /* Compare IP address */
354 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
358 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
362 switch (ip1
->sa
.sa_family
) {
364 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
365 sizeof(struct in_addr
)) == 0);
369 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
370 sizeof(struct in6_addr
)) == 0);
377 /* Append a node to a node map with given address and flags */
378 static bool node_map_add(struct ctdb_node_map
*nodemap
,
379 const char *nstr
, uint32_t flags
)
383 struct ctdb_node_and_flags
*n
;
386 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
388 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
393 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
394 struct ctdb_node_and_flags
, num
+1);
395 if (nodemap
->node
== NULL
) {
399 n
= &nodemap
->node
[num
];
404 nodemap
->num
= num
+1;
408 /* Read a nodes file into a node map */
409 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
415 struct ctdb_node_map
*nodemap
;
417 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
418 if (nodemap
== NULL
) {
422 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
427 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
431 for (i
=0; i
<nlines
; i
++) {
437 /* strip leading spaces */
438 while((*node
== ' ') || (*node
== '\t')) {
444 /* strip trailing spaces */
446 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
456 /* A "deleted" node is a node that is
457 commented out in the nodes file. This is
458 used instead of removing a line, which
459 would cause subsequent nodes to change
461 flags
= NODE_FLAGS_DELETED
;
462 node
= discard_const("0.0.0.0");
466 if (! node_map_add(nodemap
, node
, flags
)) {
468 TALLOC_FREE(nodemap
);
477 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
479 struct ctdb_node_map
*nodemap
;
480 const char *nodes_list
= NULL
;
482 const char *basedir
= getenv("CTDB_BASE");
483 if (basedir
== NULL
) {
484 basedir
= CTDB_ETCDIR
;
486 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
487 if (nodes_list
== NULL
) {
488 fprintf(stderr
, "Memory allocation error\n");
492 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
493 if (nodemap
== NULL
) {
494 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
502 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
503 struct ctdb_context
*ctdb
,
504 struct ctdb_dbid_map
*dbmap
,
507 struct ctdb_dbid
*db
= NULL
;
511 for (i
=0; i
<dbmap
->num
; i
++) {
512 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
513 ctdb
->pnn
, TIMEOUT(),
514 dbmap
->dbs
[i
].db_id
, &name
);
519 if (strcmp(db_name
, name
) == 0) {
520 talloc_free(discard_const(name
));
529 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
530 const char *db_arg
, uint32_t *db_id
,
531 const char **db_name
, uint8_t *db_flags
)
533 struct ctdb_dbid_map
*dbmap
;
534 struct ctdb_dbid
*db
= NULL
;
536 const char *name
= NULL
;
539 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
540 ctdb
->pnn
, TIMEOUT(), &dbmap
);
545 if (strncmp(db_arg
, "0x", 2) == 0) {
546 id
= strtoul(db_arg
, NULL
, 0);
547 for (i
=0; i
<dbmap
->num
; i
++) {
548 if (id
== dbmap
->dbs
[i
].db_id
) {
555 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
559 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
564 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
565 ctdb
->pnn
, TIMEOUT(), id
, &name
);
574 if (db_name
!= NULL
) {
575 *db_name
= talloc_strdup(mem_ctx
, name
);
577 if (db_flags
!= NULL
) {
578 *db_flags
= db
->flags
;
583 static int h2i(char h
)
585 if (h
>= 'a' && h
<= 'f') {
588 if (h
>= 'A' && h
<= 'F') {
594 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
601 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
606 data
.dsize
= len
/ 2;
607 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
608 if (data
.dptr
== NULL
) {
612 for (i
=0; i
<data
.dsize
; i
++) {
613 data
.dptr
[i
] = h2i(str
[i
*2]) << 4 | h2i(str
[i
*2+1]);
620 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
626 if (strncmp(str
, "0x", 2) == 0) {
627 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
629 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
630 if (data
.dptr
== NULL
) {
640 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
641 const char *path
, int argc
, const char **argv
)
644 int save_errno
, status
, ret
;
645 const char **new_argv
;
648 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
649 if (new_argv
== NULL
) {
654 for (i
=0; i
<argc
; i
++) {
655 new_argv
[i
+1] = argv
[i
];
657 new_argv
[argc
+1] = NULL
;
662 talloc_free(new_argv
);
663 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
664 command
, path
, strerror(save_errno
));
669 ret
= execv(path
, discard_const(new_argv
));
673 /* Should not happen */
677 talloc_free(new_argv
);
679 ret
= waitpid(pid
, &status
, 0);
682 fprintf(stderr
, "waitpid() failed for %s - %s\n",
683 command
, strerror(save_errno
));
687 if (WIFEXITED(status
)) {
688 int pstatus
= WEXITSTATUS(status
);
689 if (WIFSIGNALED(status
)) {
690 fprintf(stderr
, "%s terminated with signal %d\n",
691 command
, WTERMSIG(status
));
693 } else if (pstatus
>= 64 && pstatus
< 255) {
694 fprintf(stderr
, "%s failed with error %d\n",
695 command
, pstatus
-64);
701 } else if (WIFSIGNALED(status
)) {
702 fprintf(stderr
, "%s terminated with signal %d\n",
703 command
, WTERMSIG(status
));
714 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
715 int argc
, const char **argv
)
717 printf("%s\n", ctdb_version_string
);
721 static bool partially_online(TALLOC_CTX
*mem_ctx
,
722 struct ctdb_context
*ctdb
,
723 struct ctdb_node_and_flags
*node
)
725 struct ctdb_iface_list
*iface_list
;
729 if (node
->flags
!= 0) {
733 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
734 node
->pnn
, TIMEOUT(), &iface_list
);
740 for (i
=0; i
< iface_list
->num
; i
++) {
741 if (iface_list
->iface
[i
].link_state
== 0) {
750 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
751 struct ctdb_context
*ctdb
,
752 struct ctdb_node_map
*nodemap
,
755 struct ctdb_node_and_flags
*node
;
758 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
762 "Disconnected", options
.sep
,
763 "Banned", options
.sep
,
764 "Disabled", options
.sep
,
765 "Unhealthy", options
.sep
,
766 "Stopped", options
.sep
,
767 "Inactive", options
.sep
,
768 "PartiallyOnline", options
.sep
,
769 "ThisNode", options
.sep
);
771 for (i
=0; i
<nodemap
->num
; i
++) {
772 node
= &nodemap
->node
[i
];
773 if (node
->flags
& NODE_FLAGS_DELETED
) {
777 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
779 node
->pnn
, options
.sep
,
780 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
782 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
783 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
784 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
786 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
787 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
788 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
789 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
790 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
795 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
796 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
799 struct ctdb_node_and_flags
*node
;
800 int num_deleted_nodes
= 0;
803 for (i
=0; i
<nodemap
->num
; i
++) {
804 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
810 if (num_deleted_nodes
== 0) {
811 printf("Number of nodes:%d\n", nodemap
->num
);
813 printf("Number of nodes:%d "
814 "(including %d deleted nodes)\n",
815 nodemap
->num
, num_deleted_nodes
);
819 for (i
=0; i
<nodemap
->num
; i
++) {
820 node
= &nodemap
->node
[i
];
821 if (node
->flags
& NODE_FLAGS_DELETED
) {
825 printf("pnn:%u %-16s %s%s\n",
827 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
828 partially_online(mem_ctx
, ctdb
, node
) ?
830 pretty_print_flags(mem_ctx
, node
->flags
),
831 node
->pnn
== mypnn
? " (THIS NODE)" : "");
835 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
836 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
837 struct ctdb_vnn_map
*vnnmap
, int recmode
,
842 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
844 if (vnnmap
->generation
== INVALID_GENERATION
) {
845 printf("Generation:INVALID\n");
847 printf("Generation:%u\n", vnnmap
->generation
);
849 printf("Size:%d\n", vnnmap
->size
);
850 for (i
=0; i
<vnnmap
->size
; i
++) {
851 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
854 printf("Recovery mode:%s (%d)\n",
855 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
857 printf("Recovery master:%d\n", recmaster
);
860 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
861 int argc
, const char **argv
)
863 struct ctdb_node_map
*nodemap
;
864 struct ctdb_vnn_map
*vnnmap
;
873 nodemap
= get_nodemap(ctdb
, false);
874 if (nodemap
== NULL
) {
878 if (options
.machinereadable
== 1) {
879 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
883 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
884 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
889 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
890 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
895 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
896 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
901 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
906 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
907 int argc
, const char **argv
)
909 struct ctdb_uptime
*uptime
;
910 int ret
, tmp
, days
, hours
, minutes
, seconds
;
912 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
913 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
918 printf("Current time of node %-4u : %s",
919 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
921 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
922 seconds
= tmp
% 60; tmp
/= 60;
923 minutes
= tmp
% 60; tmp
/= 60;
924 hours
= tmp
% 24; tmp
/= 24;
927 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
928 days
, hours
, minutes
, seconds
,
929 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
931 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
932 seconds
= tmp
% 60; tmp
/= 60;
933 minutes
= tmp
% 60; tmp
/= 60;
934 hours
= tmp
% 24; tmp
/= 24;
937 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
938 days
, hours
, minutes
, seconds
,
939 ctime(&uptime
->last_recovery_finished
.tv_sec
));
941 printf("Duration of last recovery/failover: %lf seconds\n",
942 timeval_delta(&uptime
->last_recovery_finished
,
943 &uptime
->last_recovery_started
));
948 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
949 int argc
, const char **argv
)
952 int ret
, num_clients
;
954 tv
= timeval_current();
955 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
956 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
961 printf("response from %u time=%.6f sec (%d clients)\n",
962 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
966 const char *runstate_to_string(enum ctdb_runstate runstate
);
967 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
969 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
970 int argc
, const char **argv
)
972 enum ctdb_runstate runstate
;
976 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
977 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
983 for (i
=0; i
<argc
; i
++) {
984 enum ctdb_runstate t
;
987 t
= ctdb_runstate_from_string(argv
[i
]);
988 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
989 printf("Invalid run state (%s)\n", argv
[i
]);
1000 printf("CTDB not in required run state (got %s)\n",
1001 ctdb_runstate_to_string(runstate
));
1005 printf("%s\n", ctdb_runstate_to_string(runstate
));
1009 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1010 int argc
, const char **argv
)
1012 struct ctdb_var_list
*tun_var_list
;
1021 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1022 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1025 "Failed to get list of variables from node %u\n",
1031 for (i
=0; i
<tun_var_list
->count
; i
++) {
1032 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1039 printf("No such tunable %s\n", argv
[0]);
1043 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1044 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1049 printf("%-26s = %u\n", argv
[0], value
);
1053 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1054 int argc
, const char **argv
)
1056 struct ctdb_var_list
*tun_var_list
;
1057 struct ctdb_tunable tunable
;
1065 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1066 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1069 "Failed to get list of variables from node %u\n",
1075 for (i
=0; i
<tun_var_list
->count
; i
++) {
1076 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1083 printf("No such tunable %s\n", argv
[0]);
1087 tunable
.name
= argv
[0];
1088 tunable
.value
= strtoul(argv
[1], NULL
, 0);
1090 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1091 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1095 "Setting obsolete tunable variable '%s'\n",
1104 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1105 int argc
, const char **argv
)
1107 struct ctdb_var_list
*tun_var_list
;
1114 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1115 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1120 for (i
=0; i
<tun_var_list
->count
; i
++) {
1121 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1130 } stats_fields
[] = {
1131 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1132 STATISTICS_FIELD(num_clients
),
1133 STATISTICS_FIELD(frozen
),
1134 STATISTICS_FIELD(recovering
),
1135 STATISTICS_FIELD(num_recoveries
),
1136 STATISTICS_FIELD(client_packets_sent
),
1137 STATISTICS_FIELD(client_packets_recv
),
1138 STATISTICS_FIELD(node_packets_sent
),
1139 STATISTICS_FIELD(node_packets_recv
),
1140 STATISTICS_FIELD(keepalive_packets_sent
),
1141 STATISTICS_FIELD(keepalive_packets_recv
),
1142 STATISTICS_FIELD(node
.req_call
),
1143 STATISTICS_FIELD(node
.reply_call
),
1144 STATISTICS_FIELD(node
.req_dmaster
),
1145 STATISTICS_FIELD(node
.reply_dmaster
),
1146 STATISTICS_FIELD(node
.reply_error
),
1147 STATISTICS_FIELD(node
.req_message
),
1148 STATISTICS_FIELD(node
.req_control
),
1149 STATISTICS_FIELD(node
.reply_control
),
1150 STATISTICS_FIELD(node
.req_tunnel
),
1151 STATISTICS_FIELD(client
.req_call
),
1152 STATISTICS_FIELD(client
.req_message
),
1153 STATISTICS_FIELD(client
.req_control
),
1154 STATISTICS_FIELD(client
.req_tunnel
),
1155 STATISTICS_FIELD(timeouts
.call
),
1156 STATISTICS_FIELD(timeouts
.control
),
1157 STATISTICS_FIELD(timeouts
.traverse
),
1158 STATISTICS_FIELD(locks
.num_calls
),
1159 STATISTICS_FIELD(locks
.num_current
),
1160 STATISTICS_FIELD(locks
.num_pending
),
1161 STATISTICS_FIELD(locks
.num_failed
),
1162 STATISTICS_FIELD(total_calls
),
1163 STATISTICS_FIELD(pending_calls
),
1164 STATISTICS_FIELD(childwrite_calls
),
1165 STATISTICS_FIELD(pending_childwrite_calls
),
1166 STATISTICS_FIELD(memory_used
),
1167 STATISTICS_FIELD(max_hop_count
),
1168 STATISTICS_FIELD(total_ro_delegations
),
1169 STATISTICS_FIELD(total_ro_revokes
),
1172 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1174 static void print_statistics_machine(struct ctdb_statistics
*s
,
1180 printf("CTDB version%s", options
.sep
);
1181 printf("Current time of statistics%s", options
.sep
);
1182 printf("Statistics collected since%s", options
.sep
);
1183 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1184 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1186 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1187 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1188 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1189 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1191 printf("num_reclock_recd_latency%s", options
.sep
);
1192 printf("min_reclock_recd_latency%s", options
.sep
);
1193 printf("avg_reclock_recd_latency%s", options
.sep
);
1194 printf("max_reclock_recd_latency%s", options
.sep
);
1196 printf("num_call_latency%s", options
.sep
);
1197 printf("min_call_latency%s", options
.sep
);
1198 printf("avg_call_latency%s", options
.sep
);
1199 printf("max_call_latency%s", options
.sep
);
1201 printf("num_lockwait_latency%s", options
.sep
);
1202 printf("min_lockwait_latency%s", options
.sep
);
1203 printf("avg_lockwait_latency%s", options
.sep
);
1204 printf("max_lockwait_latency%s", options
.sep
);
1206 printf("num_childwrite_latency%s", options
.sep
);
1207 printf("min_childwrite_latency%s", options
.sep
);
1208 printf("avg_childwrite_latency%s", options
.sep
);
1209 printf("max_childwrite_latency%s", options
.sep
);
1213 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1214 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1215 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1216 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1218 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1221 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1222 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1223 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1224 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1226 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1227 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1228 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1229 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1231 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1232 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1233 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1234 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1236 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1237 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1238 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1239 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1243 static void print_statistics(struct ctdb_statistics
*s
)
1245 int tmp
, days
, hours
, minutes
, seconds
;
1247 const char *prefix
= NULL
;
1250 tmp
= s
->statistics_current_time
.tv_sec
-
1251 s
->statistics_start_time
.tv_sec
;
1252 seconds
= tmp
% 60; tmp
/= 60;
1253 minutes
= tmp
% 60; tmp
/= 60;
1254 hours
= tmp
% 24; tmp
/= 24;
1257 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1258 printf("Current time of statistics : %s",
1259 ctime(&s
->statistics_current_time
.tv_sec
));
1260 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1261 days
, hours
, minutes
, seconds
,
1262 ctime(&s
->statistics_start_time
.tv_sec
));
1264 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1265 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1266 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1268 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1269 prefix
= stats_fields
[i
].name
;
1270 printf(" %*.*s\n", preflen
-1, preflen
-1,
1271 stats_fields
[i
].name
);
1276 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1277 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1278 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1281 printf(" hop_count_buckets:");
1282 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1283 printf(" %d", s
->hop_count_bucket
[i
]);
1286 printf(" lock_buckets:");
1287 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1288 printf(" %d", s
->locks
.buckets
[i
]);
1291 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1292 "locks_latency MIN/AVG/MAX",
1293 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1294 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1296 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1297 "reclock_ctdbd MIN/AVG/MAX",
1298 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1299 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1301 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1302 "reclock_recd MIN/AVG/MAX",
1303 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1304 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1306 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1307 "call_latency MIN/AVG/MAX",
1308 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1309 s
->call_latency
.max
, s
->call_latency
.num
);
1311 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1312 "childwrite_latency MIN/AVG/MAX",
1313 s
->childwrite_latency
.min
,
1314 LATENCY_AVG(s
->childwrite_latency
),
1315 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1318 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1319 int argc
, const char **argv
)
1321 struct ctdb_statistics
*stats
;
1325 usage("statistics");
1328 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1329 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1334 if (options
.machinereadable
) {
1335 print_statistics_machine(stats
, true);
1337 print_statistics(stats
);
1343 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1344 struct ctdb_context
*ctdb
,
1345 int argc
, const char **argv
)
1350 usage("statisticsreset");
1353 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1354 ctdb
->cmd_pnn
, TIMEOUT());
1362 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1363 int argc
, const char **argv
)
1365 struct ctdb_statistics_list
*slist
;
1366 int ret
, count
= 0, i
;
1367 bool show_header
= true;
1374 count
= atoi(argv
[0]);
1377 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1378 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1383 for (i
=0; i
<slist
->num
; i
++) {
1384 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1387 if (options
.machinereadable
== 1) {
1388 print_statistics_machine(&slist
->stats
[i
],
1390 show_header
= false;
1392 print_statistics(&slist
->stats
[i
]);
1394 if (count
> 0 && i
== count
) {
1402 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1404 const struct ctdb_public_ip
*ip_a
= a
;
1405 const struct ctdb_public_ip
*ip_b
= b
;
1407 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1410 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1411 struct ctdb_public_ip_list
*ips
,
1412 struct ctdb_public_ip_info
**ipinfo
,
1416 char *conf
, *avail
, *active
;
1418 if (options
.machinereadable
== 1) {
1419 printf("%s%s%s%s%s", options
.sep
,
1420 "Public IP", options
.sep
,
1421 "Node", options
.sep
);
1422 if (options
.verbose
== 1) {
1423 printf("%s%s%s%s%s%s\n",
1424 "ActiveInterfaces", options
.sep
,
1425 "AvailableInterfaces", options
.sep
,
1426 "ConfiguredInterfaces", options
.sep
);
1432 printf("Public IPs on ALL nodes\n");
1434 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1438 for (i
= 0; i
< ips
->num
; i
++) {
1440 if (options
.machinereadable
== 1) {
1441 printf("%s%s%s%d%s", options
.sep
,
1442 ctdb_sock_addr_to_string(
1443 mem_ctx
, &ips
->ip
[i
].addr
, false),
1445 (int)ips
->ip
[i
].pnn
, options
.sep
);
1447 printf("%s", ctdb_sock_addr_to_string(
1448 mem_ctx
, &ips
->ip
[i
].addr
, false));
1451 if (options
.verbose
== 0) {
1452 if (options
.machinereadable
== 1) {
1455 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1464 if (ipinfo
[i
] == NULL
) {
1468 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1469 struct ctdb_iface
*iface
;
1471 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1473 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1475 conf
= talloc_asprintf_append(
1476 conf
, ",%s", iface
->name
);
1479 if (ipinfo
[i
]->active_idx
== j
) {
1480 active
= iface
->name
;
1483 if (iface
->link_state
== 0) {
1487 if (avail
== NULL
) {
1488 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1490 avail
= talloc_asprintf_append(
1491 avail
, ",%s", iface
->name
);
1497 if (options
.machinereadable
== 1) {
1498 printf("%s%s%s%s%s%s\n",
1499 active
? active
: "", options
.sep
,
1500 avail
? avail
: "", options
.sep
,
1501 conf
? conf
: "", options
.sep
);
1503 printf(" node[%d] active[%s] available[%s]"
1504 " configured[%s]\n",
1505 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1506 avail
? avail
: "", conf
? conf
: "");
1511 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1512 size_t datalen
, void *private_data
)
1514 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1515 private_data
, struct ctdb_public_ip_list
);
1516 struct ctdb_public_ip
*ip
;
1518 ip
= (struct ctdb_public_ip
*)databuf
;
1519 ips
->ip
[ips
->num
] = *ip
;
1525 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1526 struct ctdb_public_ip_list
**out
)
1528 struct ctdb_node_map
*nodemap
;
1529 struct ctdb_public_ip_list
*ips
;
1530 struct db_hash_context
*ipdb
;
1532 int ret
, count
, i
, j
;
1534 nodemap
= get_nodemap(ctdb
, false);
1535 if (nodemap
== NULL
) {
1539 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1544 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1550 for (i
=0; i
<count
; i
++) {
1551 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1552 pnn_list
[i
], TIMEOUT(),
1558 for (j
=0; j
<ips
->num
; j
++) {
1559 struct ctdb_public_ip ip
;
1561 ip
.pnn
= ips
->ip
[j
].pnn
;
1562 ip
.addr
= ips
->ip
[j
].addr
;
1564 if (pnn_list
[i
] == ip
.pnn
) {
1565 /* Node claims IP is hosted on it, so
1566 * save that information
1568 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1570 (uint8_t *)&ip
, sizeof(ip
));
1575 /* Node thinks IP is hosted elsewhere,
1576 * so overwrite with CTDB_UNKNOWN_PNN
1577 * if there's no existing entry
1579 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1581 if (ret
== ENOENT
) {
1582 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1583 ret
= db_hash_add(ipdb
,
1584 (uint8_t *)&ip
.addr
,
1598 talloc_free(pnn_list
);
1600 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1605 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1610 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1611 if (ips
->ip
== NULL
) {
1615 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1620 if (count
!= ips
->num
) {
1634 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1635 int argc
, const char **argv
)
1637 struct ctdb_public_ip_list
*ips
;
1638 struct ctdb_public_ip_info
**ipinfo
;
1640 bool do_all
= false;
1647 if (strcmp(argv
[0], "all") == 0) {
1655 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1657 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1658 ctdb
->cmd_pnn
, TIMEOUT(),
1665 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1666 ctdb_public_ip_cmp
);
1668 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1669 if (ipinfo
== NULL
) {
1673 for (i
=0; i
<ips
->num
; i
++) {
1676 pnn
= ips
->ip
[i
].pnn
;
1678 pnn
= ctdb
->cmd_pnn
;
1680 if (pnn
== CTDB_UNKNOWN_PNN
) {
1684 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1686 TIMEOUT(), &ips
->ip
[i
].addr
,
1693 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1697 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1698 int argc
, const char **argv
)
1700 struct ctdb_public_ip_info
*ipinfo
;
1701 ctdb_sock_addr addr
;
1708 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1710 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1714 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1715 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1719 printf("Node %u does not know about IP %s\n",
1720 ctdb
->cmd_pnn
, argv
[0]);
1725 printf("Public IP[%s] info on node %u\n",
1726 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1729 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1730 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1731 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1733 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1734 struct ctdb_iface
*iface
;
1736 iface
= &ipinfo
->ifaces
->iface
[i
];
1737 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1738 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1740 iface
->link_state
== 0 ? "down" : "up",
1742 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1748 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1749 int argc
, const char **argv
)
1751 struct ctdb_iface_list
*ifaces
;
1758 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1759 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1764 if (ifaces
->num
== 0) {
1765 printf("No interfaces configured on node %u\n",
1770 if (options
.machinereadable
) {
1771 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1772 "Name", options
.sep
,
1773 "LinkStatus", options
.sep
,
1774 "References", options
.sep
);
1776 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1779 for (i
=0; i
<ifaces
->num
; i
++) {
1780 if (options
.machinereadable
) {
1781 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1782 ifaces
->iface
[i
].name
, options
.sep
,
1783 ifaces
->iface
[i
].link_state
, options
.sep
,
1784 ifaces
->iface
[i
].references
, options
.sep
);
1786 printf("name:%s link:%s references:%u\n",
1787 ifaces
->iface
[i
].name
,
1788 ifaces
->iface
[i
].link_state
? "up" : "down",
1789 ifaces
->iface
[i
].references
);
1796 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1797 int argc
, const char **argv
)
1799 struct ctdb_iface_list
*ifaces
;
1800 struct ctdb_iface
*iface
;
1804 usage("setifacelink");
1807 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1808 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1812 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1813 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1816 "Failed to get interface information from node %u\n",
1822 for (i
=0; i
<ifaces
->num
; i
++) {
1823 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1824 iface
= &ifaces
->iface
[i
];
1829 if (iface
== NULL
) {
1830 printf("Interface %s not configured on node %u\n",
1831 argv
[0], ctdb
->cmd_pnn
);
1835 if (strcmp(argv
[1], "up") == 0) {
1836 iface
->link_state
= 1;
1837 } else if (strcmp(argv
[1], "down") == 0) {
1838 iface
->link_state
= 0;
1840 usage("setifacelink");
1844 iface
->references
= 0;
1846 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1847 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1855 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1856 struct ctdb_context
*ctdb
,
1857 int argc
, const char **argv
)
1863 if (argc
!= 1 && argc
!= 2) {
1864 usage("process-exists");
1867 pid
= atoi(argv
[0]);
1869 srvid
= strtoull(argv
[1], NULL
, 0);
1873 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1874 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1876 struct ctdb_pid_srvid pid_srvid
;
1878 pid_srvid
.pid
= pid
;
1879 pid_srvid
.srvid
= srvid
;
1881 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
1882 ctdb
->client
, ctdb
->cmd_pnn
,
1883 TIMEOUT(), &pid_srvid
,
1892 printf("PID %d %s\n", pid
,
1893 (status
== 0 ? "exists" : "does not exist"));
1895 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
1896 (status
== 0 ? "exists" : "does not exist"));
1901 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1902 int argc
, const char **argv
)
1904 struct ctdb_dbid_map
*dbmap
;
1911 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1912 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1917 if (options
.machinereadable
== 1) {
1918 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1921 "Name", options
.sep
,
1922 "Path", options
.sep
,
1923 "Persistent", options
.sep
,
1924 "Sticky", options
.sep
,
1925 "Unhealthy", options
.sep
,
1926 "Readonly", options
.sep
,
1927 "Replicated", options
.sep
);
1929 printf("Number of databases:%d\n", dbmap
->num
);
1932 for (i
=0; i
<dbmap
->num
; i
++) {
1942 db_id
= dbmap
->dbs
[i
].db_id
;
1944 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1945 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1951 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1952 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1958 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1959 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1965 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
1966 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
1967 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
1968 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
1970 if (options
.machinereadable
== 1) {
1971 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1976 !! (persistent
), options
.sep
,
1977 !! (sticky
), options
.sep
,
1978 !! (health
), options
.sep
,
1979 !! (readonly
), options
.sep
,
1980 !! (replicated
), options
.sep
);
1982 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1984 persistent
? " PERSISTENT" : "",
1985 sticky
? " STICKY" : "",
1986 readonly
? " READONLY" : "",
1987 replicated
? " REPLICATED" : "",
1988 health
? " UNHEALTHY" : "");
1991 talloc_free(discard_const(name
));
1992 talloc_free(discard_const(path
));
1993 talloc_free(discard_const(health
));
1999 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2000 int argc
, const char **argv
)
2003 const char *db_name
, *db_path
, *db_health
;
2008 usage("getdbstatus");
2011 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2015 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2016 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2022 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2023 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2029 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2030 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2031 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2032 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2033 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2034 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2035 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2039 struct dump_record_state
{
2043 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2045 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2049 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2050 for (i
=0; i
<val
.dsize
; i
++) {
2051 if (ISASCII(val
.dptr
[i
])) {
2052 fprintf(stdout
, "%c", val
.dptr
[i
]);
2054 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2057 fprintf(stdout
, "\"\n");
2060 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2062 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2063 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2064 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2065 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2066 fprintf(stdout
, " MIGRATED_WITH_DATA");
2068 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2069 fprintf(stdout
, " VACUUM_MIGRATED");
2071 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2072 fprintf(stdout
, " AUTOMATIC");
2074 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2075 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2077 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2078 fprintf(stdout
, " RO_HAVE_READONLY");
2080 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2081 fprintf(stdout
, " RO_REVOKING_READONLY");
2083 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2084 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2086 fprintf(stdout
, "\n");
2090 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2091 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2093 struct dump_record_state
*state
=
2094 (struct dump_record_state
*)private_data
;
2098 dump_tdb_data("key", key
);
2099 dump_ltdb_header(header
);
2100 dump_tdb_data("data", data
);
2101 fprintf(stdout
, "\n");
2106 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2107 int argc
, const char **argv
)
2109 struct ctdb_db_context
*db
;
2110 const char *db_name
;
2113 struct dump_record_state state
;
2120 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2124 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2127 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2133 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2134 ctdb
->cmd_pnn
, TIMEOUT(),
2135 dump_record
, &state
);
2137 printf("Dumped %u records\n", state
.count
);
2142 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2143 int argc
, const char **argv
)
2145 struct ctdb_db_context
*db
;
2146 const char *db_name
;
2149 struct dump_record_state state
;
2156 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2160 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2163 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2168 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2170 printf("Dumped %u record(s)\n", state
.count
);
2175 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2176 struct ctdb_context
*ctdb
,
2177 int argc
, const char **argv
)
2183 usage("getcapabilities");
2186 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2187 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2192 if (options
.machinereadable
== 1) {
2193 printf("%s%s%s%s%s\n",
2195 "RECMASTER", options
.sep
,
2196 "LMASTER", options
.sep
);
2197 printf("%s%d%s%d%s\n", options
.sep
,
2198 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2199 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2201 printf("RECMASTER: %s\n",
2202 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2203 printf("LMASTER: %s\n",
2204 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2210 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2211 int argc
, const char **argv
)
2213 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2217 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2218 int argc
, const char **argv
)
2220 char *t
, *lvs_helper
= NULL
;
2226 t
= getenv("CTDB_LVS_HELPER");
2228 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2230 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2231 CTDB_HELPER_BINDIR
);
2234 if (lvs_helper
== NULL
) {
2235 fprintf(stderr
, "Unable to set LVS helper\n");
2239 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2242 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2243 int argc
, const char **argv
)
2253 found
= debug_level_parse(argv
[0], &log_level
);
2256 "Invalid debug level '%s'. Valid levels are:\n",
2258 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2262 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2263 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2271 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2272 int argc
, const char **argv
)
2275 const char *log_str
;
2282 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2283 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2288 log_str
= debug_level_to_string(loglevel
);
2289 printf("%s\n", log_str
);
2294 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2295 int argc
, const char **argv
)
2297 const char *db_name
;
2298 uint8_t db_flags
= 0;
2301 if (argc
< 1 || argc
> 2) {
2307 if (strcmp(argv
[1], "persistent") == 0) {
2308 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2309 } else if (strcmp(argv
[1], "readonly") == 0) {
2310 db_flags
= CTDB_DB_FLAGS_READONLY
;
2311 } else if (strcmp(argv
[1], "sticky") == 0) {
2312 db_flags
= CTDB_DB_FLAGS_STICKY
;
2313 } else if (strcmp(argv
[1], "replicated") == 0) {
2314 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2320 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2329 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2330 int argc
, const char **argv
)
2332 const char *db_name
;
2335 struct ctdb_node_map
*nodemap
;
2343 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2344 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2349 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2350 fprintf(stderr
, "Database cannot be detached"
2351 " when recovery is active\n");
2355 nodemap
= get_nodemap(ctdb
, false);
2356 if (nodemap
== NULL
) {
2360 for (i
=0; i
<nodemap
->num
; i
++) {
2363 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
2366 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
2369 if (nodemap
->node
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2370 fprintf(stderr
, "Database cannot be detached on"
2371 " inactive (stopped or banned) node %u\n",
2372 nodemap
->node
[i
].pnn
);
2376 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2377 nodemap
->node
[i
].pnn
, TIMEOUT(),
2378 "AllowClientDBAttach", &value
);
2381 "Unable to get tunable AllowClientDBAttach"
2382 " from node %u\n", nodemap
->node
[i
].pnn
);
2388 "Database access is still active on node %u."
2389 " Set AllowclientDBAttach=0 on all nodes.\n",
2390 nodemap
->node
[i
].pnn
);
2396 for (i
=0; i
<argc
; i
++) {
2397 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2403 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2405 "Only volatile databases can be detached\n");
2409 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2411 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2419 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2420 int argc
, const char **argv
)
2422 const char *mem_str
;
2426 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2427 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2432 n
= write(1, mem_str
, strlen(mem_str
)+1);
2433 if (n
< 0 || n
!= strlen(mem_str
)+1) {
2434 fprintf(stderr
, "Failed to write talloc summary\n");
2441 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2443 bool *done
= (bool *)private_data
;
2446 n
= write(1, data
.dptr
, data
.dsize
);
2447 if (n
< 0 || n
!= data
.dsize
) {
2448 fprintf(stderr
, "Failed to write talloc summary\n");
2454 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2455 int argc
, const char **argv
)
2457 struct ctdb_srvid_message msg
= { 0 };
2461 msg
.pnn
= ctdb
->pnn
;
2462 msg
.srvid
= next_srvid(ctdb
);
2464 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2465 msg
.srvid
, dump_memory
, &done
);
2470 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2471 ctdb
->cmd_pnn
, &msg
);
2476 ctdb_client_wait(ctdb
->ev
, &done
);
2480 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2481 int argc
, const char **argv
)
2486 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2487 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2492 printf("%u\n", pid
);
2496 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2497 const char *desc
, uint32_t flag
, bool set_flag
)
2499 struct ctdb_node_map
*nodemap
;
2502 nodemap
= get_nodemap(ctdb
, false);
2503 if (nodemap
== NULL
) {
2507 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2508 if (set_flag
== flag_is_set
) {
2510 fprintf(stderr
, "Node %u is already %s\n",
2511 ctdb
->cmd_pnn
, desc
);
2513 fprintf(stderr
, "Node %u is not %s\n",
2514 ctdb
->cmd_pnn
, desc
);
2522 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2523 uint32_t flag
, bool set_flag
)
2525 struct ctdb_node_map
*nodemap
;
2529 nodemap
= get_nodemap(ctdb
, true);
2530 if (nodemap
== NULL
) {
2532 "Failed to get nodemap, trying again\n");
2537 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2538 if (flag_is_set
== set_flag
) {
2546 static int ctdb_ctrl_modflags(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
2547 struct ctdb_client_context
*client
,
2548 uint32_t destnode
, struct timeval timeout
,
2549 uint32_t set
, uint32_t clear
)
2551 struct ctdb_node_map
*nodemap
;
2552 struct ctdb_node_flag_change flag_change
;
2553 struct ctdb_req_control request
;
2557 ret
= ctdb_ctrl_get_nodemap(mem_ctx
, ev
, client
, destnode
,
2558 tevent_timeval_zero(), &nodemap
);
2563 flag_change
.pnn
= destnode
;
2564 flag_change
.old_flags
= nodemap
->node
[destnode
].flags
;
2565 flag_change
.new_flags
= flag_change
.old_flags
| set
;
2566 flag_change
.new_flags
&= ~clear
;
2568 count
= list_of_connected_nodes(nodemap
, -1, mem_ctx
, &pnn_list
);
2573 ctdb_req_control_modify_flags(&request
, &flag_change
);
2574 ret
= ctdb_client_control_multi(mem_ctx
, ev
, client
, pnn_list
, count
,
2575 tevent_timeval_zero(), &request
,
2580 struct ipreallocate_state
{
2585 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2588 struct ipreallocate_state
*state
=
2589 (struct ipreallocate_state
*)private_data
;
2591 if (data
.dsize
!= sizeof(int)) {
2596 state
->status
= *(int *)data
.dptr
;
2600 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2602 struct ctdb_srvid_message msg
= { 0 };
2603 struct ipreallocate_state state
;
2606 msg
.pnn
= ctdb
->pnn
;
2607 msg
.srvid
= next_srvid(ctdb
);
2610 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2612 ipreallocate_handler
, &state
);
2618 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2620 CTDB_BROADCAST_CONNECTED
,
2626 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2632 if (state
.status
>= 0) {
2641 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2646 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2647 int argc
, const char **argv
)
2655 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2656 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2661 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2662 ctdb
->cmd_pnn
, TIMEOUT(),
2663 NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2666 "Failed to set DISABLED flag on node %u\n",
2671 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2672 return ipreallocate(mem_ctx
, ctdb
);
2675 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2676 int argc
, const char **argv
)
2684 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2685 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2690 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2691 ctdb
->cmd_pnn
, TIMEOUT(),
2692 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2694 fprintf(stderr
, "Failed to reset DISABLED flag on node %u\n",
2699 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2700 return ipreallocate(mem_ctx
, ctdb
);
2703 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2704 int argc
, const char **argv
)
2712 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2713 NODE_FLAGS_STOPPED
, true);
2718 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2719 ctdb
->cmd_pnn
, TIMEOUT());
2721 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2725 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2726 return ipreallocate(mem_ctx
, ctdb
);
2729 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2730 int argc
, const char **argv
)
2738 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2739 NODE_FLAGS_STOPPED
, false);
2744 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2745 ctdb
->cmd_pnn
, TIMEOUT());
2747 fprintf(stderr
, "Failed to continue stopped node %u\n",
2752 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2753 return ipreallocate(mem_ctx
, ctdb
);
2756 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2757 int argc
, const char **argv
)
2759 struct ctdb_ban_state ban_state
;
2766 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2767 NODE_FLAGS_BANNED
, true);
2772 ban_state
.pnn
= ctdb
->cmd_pnn
;
2773 ban_state
.time
= strtoul(argv
[0], NULL
, 0);
2775 if (ban_state
.time
== 0) {
2776 fprintf(stderr
, "Ban time cannot be zero\n");
2780 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2781 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2783 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2787 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2788 return ipreallocate(mem_ctx
, ctdb
);
2792 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2793 int argc
, const char **argv
)
2795 struct ctdb_ban_state ban_state
;
2802 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2803 NODE_FLAGS_BANNED
, false);
2808 ban_state
.pnn
= ctdb
->cmd_pnn
;
2811 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2812 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2814 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2818 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2819 return ipreallocate(mem_ctx
, ctdb
);
2823 static void wait_for_shutdown(void *private_data
)
2825 bool *done
= (bool *)private_data
;
2830 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2831 int argc
, const char **argv
)
2840 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2841 ctdb_client_set_disconnect_callback(ctdb
->client
,
2846 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2847 ctdb
->cmd_pnn
, TIMEOUT());
2849 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2853 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2854 ctdb_client_wait(ctdb
->ev
, &done
);
2860 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2861 uint32_t *generation
)
2865 struct ctdb_vnn_map
*vnnmap
;
2869 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2870 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2872 fprintf(stderr
, "Failed to find recovery master\n");
2876 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2877 recmaster
, TIMEOUT(), &recmode
);
2879 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2884 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2889 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2890 recmaster
, TIMEOUT(), &vnnmap
);
2892 fprintf(stderr
, "Failed to get generation from node %u\n",
2897 if (vnnmap
->generation
== INVALID_GENERATION
) {
2898 talloc_free(vnnmap
);
2903 *generation
= vnnmap
->generation
;
2904 talloc_free(vnnmap
);
2909 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2910 int argc
, const char **argv
)
2912 uint32_t generation
, next_generation
;
2919 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2924 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2925 ctdb
->cmd_pnn
, TIMEOUT(),
2926 CTDB_RECOVERY_ACTIVE
);
2928 fprintf(stderr
, "Failed to set recovery mode active\n");
2933 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2936 "Failed to confirm end of recovery\n");
2940 if (next_generation
!= generation
) {
2950 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2951 int argc
, const char **argv
)
2954 usage("ipreallocate");
2957 return ipreallocate(mem_ctx
, ctdb
);
2960 static int control_isnotrecmaster(TALLOC_CTX
*mem_ctx
,
2961 struct ctdb_context
*ctdb
,
2962 int argc
, const char **argv
)
2968 usage("isnotrecmaster");
2971 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2972 ctdb
->pnn
, TIMEOUT(), &recmaster
);
2974 fprintf(stderr
, "Failed to get recmaster\n");
2978 if (recmaster
!= ctdb
->pnn
) {
2979 printf("this node is not the recmaster\n");
2983 printf("this node is the recmaster\n");
2987 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2988 int argc
, const char **argv
)
2990 struct ctdb_addr_info addr_info
;
2997 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
2999 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3002 addr_info
.iface
= argv
[1];
3004 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3005 ctdb
->cmd_pnn
, TIMEOUT(),
3008 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3016 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3017 int argc
, const char **argv
)
3019 ctdb_sock_addr src
, dst
;
3022 if (argc
!= 0 && argc
!= 2) {
3027 struct ctdb_connection_list
*clist
;
3029 unsigned int num_failed
;
3031 /* Client first but the src/dst logic is confused */
3032 ret
= ctdb_connection_list_read(mem_ctx
, false, &clist
);
3038 for (i
= 0; i
< clist
->num
; i
++) {
3039 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3040 &clist
->conn
[i
].dst
,
3049 if (num_failed
> 0) {
3050 fprintf(stderr
, "Failed to send %d tickles\n",
3059 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3061 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3065 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3067 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3071 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3073 fprintf(stderr
, "Failed to send tickle ack\n");
3080 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3081 int argc
, const char **argv
)
3083 ctdb_sock_addr addr
;
3084 struct ctdb_tickle_list
*tickles
;
3088 if (argc
< 1 || argc
> 2) {
3089 usage("gettickles");
3093 port
= strtoul(argv
[1], NULL
, 10);
3096 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3098 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3101 ctdb_sock_addr_set_port(&addr
, port
);
3103 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3104 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3107 fprintf(stderr
, "Failed to get list of connections\n");
3111 if (options
.machinereadable
) {
3112 printf("%s%s%s%s%s%s%s%s%s\n",
3114 "Source IP", options
.sep
,
3115 "Port", options
.sep
,
3116 "Destiation IP", options
.sep
,
3117 "Port", options
.sep
);
3118 for (i
=0; i
<tickles
->num
; i
++) {
3119 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3120 ctdb_sock_addr_to_string(
3121 mem_ctx
, &tickles
->conn
[i
].src
, false),
3123 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3125 ctdb_sock_addr_to_string(
3126 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3128 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3132 printf("Connections for IP: %s\n",
3133 ctdb_sock_addr_to_string(mem_ctx
,
3134 &tickles
->addr
, false));
3135 printf("Num connections: %u\n", tickles
->num
);
3136 for (i
=0; i
<tickles
->num
; i
++) {
3137 printf("SRC: %s DST: %s\n",
3138 ctdb_sock_addr_to_string(
3139 mem_ctx
, &tickles
->conn
[i
].src
, true),
3140 ctdb_sock_addr_to_string(
3141 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3145 talloc_free(tickles
);
3149 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3150 struct ctdb_connection
*conn
);
3152 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3154 struct process_clist_state
{
3155 struct ctdb_connection_list
*clist
;
3157 int num_failed
, num_total
;
3158 clist_reply_func reply_func
;
3161 static void process_clist_done(struct tevent_req
*subreq
);
3163 static struct tevent_req
*process_clist_send(
3164 TALLOC_CTX
*mem_ctx
,
3165 struct ctdb_context
*ctdb
,
3166 struct ctdb_connection_list
*clist
,
3167 clist_request_func request_func
,
3168 clist_reply_func reply_func
)
3170 struct tevent_req
*req
, *subreq
;
3171 struct process_clist_state
*state
;
3172 struct ctdb_req_control request
;
3175 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3180 state
->clist
= clist
;
3181 state
->reply_func
= reply_func
;
3183 for (i
= 0; i
< clist
->num
; i
++) {
3184 request_func(&request
, &clist
->conn
[i
]);
3185 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3186 ctdb
->client
, ctdb
->cmd_pnn
,
3187 TIMEOUT(), &request
);
3188 if (tevent_req_nomem(subreq
, req
)) {
3189 return tevent_req_post(req
, ctdb
->ev
);
3191 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3197 static void process_clist_done(struct tevent_req
*subreq
)
3199 struct tevent_req
*req
= tevent_req_callback_data(
3200 subreq
, struct tevent_req
);
3201 struct process_clist_state
*state
= tevent_req_data(
3202 req
, struct process_clist_state
);
3203 struct ctdb_reply_control
*reply
;
3207 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3208 TALLOC_FREE(subreq
);
3210 state
->num_failed
+= 1;
3214 ret
= state
->reply_func(reply
);
3216 state
->num_failed
+= 1;
3221 state
->num_total
+= 1;
3222 if (state
->num_total
== state
->clist
->num
) {
3223 tevent_req_done(req
);
3227 static int process_clist_recv(struct tevent_req
*req
)
3229 struct process_clist_state
*state
= tevent_req_data(
3230 req
, struct process_clist_state
);
3232 return state
->num_failed
;
3235 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3236 int argc
, const char **argv
)
3238 struct ctdb_connection conn
;
3241 if (argc
!= 0 && argc
!= 2) {
3246 struct ctdb_connection_list
*clist
;
3247 struct tevent_req
*req
;
3249 /* Client first but the src/dst logic is confused */
3250 ret
= ctdb_connection_list_read(mem_ctx
, false, &clist
);
3254 if (clist
->num
== 0) {
3258 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3259 ctdb_req_control_tcp_add_delayed_update
,
3260 ctdb_reply_control_tcp_add_delayed_update
);
3266 tevent_req_poll(req
, ctdb
->ev
);
3269 ret
= process_clist_recv(req
);
3271 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3278 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3280 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3283 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3285 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3289 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3290 ctdb
->client
, ctdb
->cmd_pnn
,
3293 fprintf(stderr
, "Failed to register connection\n");
3300 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3301 int argc
, const char **argv
)
3303 struct ctdb_connection conn
;
3306 if (argc
!= 0 && argc
!= 2) {
3311 struct ctdb_connection_list
*clist
;
3312 struct tevent_req
*req
;
3314 /* Client first but the src/dst logic is confused */
3315 ret
= ctdb_connection_list_read(mem_ctx
, false, &clist
);
3319 if (clist
->num
== 0) {
3323 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3324 ctdb_req_control_tcp_remove
,
3325 ctdb_reply_control_tcp_remove
);
3331 tevent_req_poll(req
, ctdb
->ev
);
3334 ret
= process_clist_recv(req
);
3336 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3343 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3345 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3348 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3350 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3354 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3355 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3357 fprintf(stderr
, "Failed to unregister connection\n");
3364 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3365 int argc
, const char **argv
)
3367 struct ctdb_node_map
*nodemap
;
3374 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3375 if (nodemap
== NULL
) {
3379 for (i
=0; i
<nodemap
->num
; i
++) {
3380 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3384 if (options
.machinereadable
) {
3385 printf("%s%u%s%s%s\n", options
.sep
,
3386 nodemap
->node
[i
].pnn
, options
.sep
,
3387 ctdb_sock_addr_to_string(
3388 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3392 ctdb_sock_addr_to_string(
3393 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3400 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3401 struct ctdb_node_map
*nodemap2
)
3405 if (nodemap1
->num
!= nodemap2
->num
) {
3409 for (i
=0; i
<nodemap1
->num
; i
++) {
3410 struct ctdb_node_and_flags
*n1
, *n2
;
3412 n1
= &nodemap1
->node
[i
];
3413 n2
= &nodemap2
->node
[i
];
3415 if ((n1
->pnn
!= n2
->pnn
) ||
3416 (n1
->flags
!= n2
->flags
) ||
3417 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3425 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3426 struct ctdb_node_map
*nm
,
3427 struct ctdb_node_map
*fnm
,
3431 bool check_failed
= false;
3435 for (i
=0; i
<nm
->num
; i
++) {
3436 if (i
>= fnm
->num
) {
3438 "Node %u (%s) missing from nodes file\n",
3440 ctdb_sock_addr_to_string(
3441 mem_ctx
, &nm
->node
[i
].addr
, false));
3442 check_failed
= true;
3445 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3446 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3447 /* Node remains deleted */
3451 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3452 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3453 /* Node not newly nor previously deleted */
3454 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3455 &fnm
->node
[i
].addr
)) {
3457 "Node %u has changed IP address"
3458 " (was %s, now %s)\n",
3460 ctdb_sock_addr_to_string(
3462 &nm
->node
[i
].addr
, false),
3463 ctdb_sock_addr_to_string(
3465 &fnm
->node
[i
].addr
, false));
3466 check_failed
= true;
3468 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3470 "WARNING: Node %u is disconnected."
3471 " You MUST fix this node manually!\n",
3478 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3479 /* Node is being deleted */
3480 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3482 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3484 "ERROR: Node %u is still connected\n",
3486 check_failed
= true;
3491 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3492 /* Node was previously deleted */
3493 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3500 "ERROR: Nodes will not be reloaded due to previous error\n");
3504 /* Leftover nodes in file are NEW */
3505 for (; i
< fnm
->num
; i
++) {
3506 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3513 struct disable_recoveries_state
{
3521 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3524 struct disable_recoveries_state
*state
=
3525 (struct disable_recoveries_state
*)private_data
;
3528 if (data
.dsize
!= sizeof(int)) {
3533 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3534 ret
= *(int *)data
.dptr
;
3536 state
->status
= ret
;
3540 for (i
=0; i
<state
->node_count
; i
++) {
3541 if (state
->pnn_list
[i
] == ret
) {
3542 state
->reply
[i
] = true;
3548 for (i
=0; i
<state
->node_count
; i
++) {
3549 if (! state
->reply
[i
]) {
3550 state
->done
= false;
3556 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3557 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3559 struct ctdb_disable_message disable
= { 0 };
3560 struct disable_recoveries_state state
;
3563 disable
.pnn
= ctdb
->pnn
;
3564 disable
.srvid
= next_srvid(ctdb
);
3565 disable
.timeout
= timeout
;
3567 state
.pnn_list
= pnn_list
;
3568 state
.node_count
= count
;
3571 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3572 if (state
.reply
== NULL
) {
3576 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3578 disable_recoveries_handler
,
3584 for (i
=0; i
<count
; i
++) {
3585 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3594 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3596 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3598 ret
= (state
.status
>= 0 ? 0 : 1);
3602 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3603 disable
.srvid
, &state
);
3607 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3608 int argc
, const char **argv
)
3610 struct ctdb_node_map
*nodemap
= NULL
;
3611 struct ctdb_node_map
*file_nodemap
;
3612 struct ctdb_node_map
*remote_nodemap
;
3613 struct ctdb_req_control request
;
3614 struct ctdb_reply_control
**reply
;
3620 nodemap
= get_nodemap(ctdb
, false);
3621 if (nodemap
== NULL
) {
3625 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3626 if (file_nodemap
== NULL
) {
3630 for (i
=0; i
<nodemap
->num
; i
++) {
3631 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3635 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3636 nodemap
->node
[i
].pnn
, TIMEOUT(),
3640 "ERROR: Failed to get nodes file from node %u\n",
3641 nodemap
->node
[i
].pnn
);
3645 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3647 "ERROR: Nodes file on node %u differs"
3648 " from current node (%u)\n",
3649 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3654 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3660 fprintf(stderr
, "No change in nodes file,"
3661 " skipping unnecessary reload\n");
3665 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3666 mem_ctx
, &pnn_list
);
3668 fprintf(stderr
, "Memory allocation error\n");
3672 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3675 fprintf(stderr
, "Failed to disable recoveries\n");
3679 ctdb_req_control_reload_nodes_file(&request
);
3680 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3681 pnn_list
, count
, TIMEOUT(),
3682 &request
, NULL
, &reply
);
3684 bool failed
= false;
3686 for (i
=0; i
<count
; i
++) {
3687 ret
= ctdb_reply_control_reload_nodes_file(reply
[i
]);
3690 "Node %u failed to reload nodes\n",
3697 "You MUST fix failed nodes manually!\n");
3701 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3703 fprintf(stderr
, "Failed to enable recoveries\n");
3710 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3711 ctdb_sock_addr
*addr
, uint32_t pnn
)
3713 struct ctdb_public_ip_list
*pubip_list
;
3714 struct ctdb_public_ip pubip
;
3715 struct ctdb_node_map
*nodemap
;
3716 struct ctdb_req_control request
;
3720 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3721 CTDB_BROADCAST_CONNECTED
,
3722 2*options
.timelimit
);
3724 fprintf(stderr
, "Failed to disable IP check\n");
3728 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3729 pnn
, TIMEOUT(), false, &pubip_list
);
3731 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3736 for (i
=0; i
<pubip_list
->num
; i
++) {
3737 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3742 if (i
== pubip_list
->num
) {
3743 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3744 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3748 nodemap
= get_nodemap(ctdb
, false);
3749 if (nodemap
== NULL
) {
3753 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3755 fprintf(stderr
, "Memory allocation error\n");
3761 ctdb_req_control_release_ip(&request
, &pubip
);
3763 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3764 pnn_list
, count
, TIMEOUT(),
3765 &request
, NULL
, NULL
);
3767 fprintf(stderr
, "Failed to release IP on nodes\n");
3771 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3772 pnn
, TIMEOUT(), &pubip
);
3774 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3781 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3782 int argc
, const char **argv
)
3784 ctdb_sock_addr addr
;
3786 int ret
, retries
= 0;
3792 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3794 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3798 pnn
= strtoul(argv
[1], NULL
, 10);
3799 if (pnn
== CTDB_UNKNOWN_PNN
) {
3800 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3804 while (retries
< 5) {
3805 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3815 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3823 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3828 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3829 CTDB_BROADCAST_CONNECTED
, pnn
);
3832 "Failed to ask recovery master to distribute IPs\n");
3839 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3840 int argc
, const char **argv
)
3842 ctdb_sock_addr addr
;
3843 struct ctdb_public_ip_list
*pubip_list
;
3844 struct ctdb_addr_info addr_info
;
3846 int ret
, i
, retries
= 0;
3852 if (! parse_ip_mask(argv
[0], argv
[1], &addr
, &mask
)) {
3853 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3857 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3858 ctdb
->cmd_pnn
, TIMEOUT(),
3859 false, &pubip_list
);
3861 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3866 for (i
=0; i
<pubip_list
->num
; i
++) {
3867 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3868 fprintf(stderr
, "Node already knows about IP %s\n",
3869 ctdb_sock_addr_to_string(mem_ctx
,
3875 addr_info
.addr
= addr
;
3876 addr_info
.mask
= mask
;
3877 addr_info
.iface
= argv
[1];
3879 while (retries
< 5) {
3880 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3881 ctdb
->cmd_pnn
, TIMEOUT(),
3892 fprintf(stderr
, "Failed to add public IP to node %u."
3893 " Giving up\n", ctdb
->cmd_pnn
);
3897 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3905 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3906 int argc
, const char **argv
)
3908 ctdb_sock_addr addr
;
3909 struct ctdb_public_ip_list
*pubip_list
;
3910 struct ctdb_addr_info addr_info
;
3917 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3919 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3923 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3924 ctdb
->cmd_pnn
, TIMEOUT(),
3925 false, &pubip_list
);
3927 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3932 for (i
=0; i
<pubip_list
->num
; i
++) {
3933 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3938 if (i
== pubip_list
->num
) {
3939 fprintf(stderr
, "Node does not know about IP address %s\n",
3940 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
3944 addr_info
.addr
= addr
;
3946 addr_info
.iface
= NULL
;
3948 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3949 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
3951 fprintf(stderr
, "Failed to delete public IP from node %u\n",
3959 #define DB_VERSION 3
3960 #define MAX_DB_NAME 64
3961 #define MAX_REC_BUFFER_SIZE (100*1000)
3964 unsigned long version
;
3966 unsigned long flags
;
3969 char name
[MAX_DB_NAME
];
3972 struct backup_state
{
3973 TALLOC_CTX
*mem_ctx
;
3974 struct ctdb_rec_buffer
*recbuf
;
3977 unsigned int nbuf
, nrec
;
3980 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
3981 TDB_DATA key
, TDB_DATA data
, void *private_data
)
3983 struct backup_state
*state
= (struct backup_state
*)private_data
;
3987 if (state
->recbuf
== NULL
) {
3988 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
3990 if (state
->recbuf
== NULL
) {
3995 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4001 len
= ctdb_rec_buffer_len(state
->recbuf
);
4002 if (len
< MAX_REC_BUFFER_SIZE
) {
4006 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4008 fprintf(stderr
, "Failed to write records to backup file\n");
4013 state
->nrec
+= state
->recbuf
->count
;
4014 TALLOC_FREE(state
->recbuf
);
4019 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4020 int argc
, const char **argv
)
4022 const char *db_name
;
4023 struct ctdb_db_context
*db
;
4026 struct backup_state state
;
4027 struct db_header db_hdr
;
4034 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4038 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4041 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4045 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4048 fprintf(stderr
, "Failed to open file %s for writing\n",
4053 /* Write empty header first */
4054 ZERO_STRUCT(db_hdr
);
4055 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4059 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4063 state
.mem_ctx
= mem_ctx
;
4064 state
.recbuf
= NULL
;
4069 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4071 fprintf(stderr
, "Failed to collect records from DB %s\n",
4077 if (state
.recbuf
!= NULL
) {
4078 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4081 "Failed to write records to backup file\n");
4087 state
.nrec
+= state
.recbuf
->count
;
4088 TALLOC_FREE(state
.recbuf
);
4091 db_hdr
.version
= DB_VERSION
;
4092 db_hdr
.timestamp
= time(NULL
);
4093 db_hdr
.flags
= db_flags
;
4094 db_hdr
.nbuf
= state
.nbuf
;
4095 db_hdr
.nrec
= state
.nrec
;
4096 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4098 lseek(fd
, 0, SEEK_SET
);
4099 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4103 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4108 printf("Database backed up to %s\n", argv
[1]);
4112 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4113 int argc
, const char **argv
)
4115 const char *db_name
= NULL
;
4116 struct ctdb_db_context
*db
;
4117 struct db_header db_hdr
;
4118 struct ctdb_node_map
*nodemap
;
4119 struct ctdb_req_control request
;
4120 struct ctdb_reply_control
**reply
;
4121 struct ctdb_transdb wipedb
;
4122 struct ctdb_pulldb_ext pulldb
;
4123 struct ctdb_rec_buffer
*recbuf
;
4124 uint32_t generation
;
4132 if (argc
< 1 || argc
> 2) {
4136 fd
= open(argv
[0], O_RDONLY
, 0600);
4139 fprintf(stderr
, "Failed to open file %s for reading\n",
4148 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4152 fprintf(stderr
, "Failed to read db header from file %s\n",
4156 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4158 if (db_hdr
.version
!= DB_VERSION
) {
4160 "Wrong version of backup file, expected %u, got %lu\n",
4161 DB_VERSION
, db_hdr
.version
);
4166 if (db_name
== NULL
) {
4167 db_name
= db_hdr
.name
;
4170 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4171 localtime(&db_hdr
.timestamp
));
4172 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4174 db_flags
= db_hdr
.flags
& 0xff;
4175 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4178 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4183 nodemap
= get_nodemap(ctdb
, false);
4184 if (nodemap
== NULL
) {
4185 fprintf(stderr
, "Failed to get nodemap\n");
4190 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4192 fprintf(stderr
, "Failed to get current generation\n");
4197 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4204 wipedb
.db_id
= ctdb_db_id(db
);
4205 wipedb
.tid
= generation
;
4207 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4208 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4209 ctdb
->client
, pnn_list
, count
,
4210 TIMEOUT(), &request
, NULL
, NULL
);
4216 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4217 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4218 pnn_list
, count
, TIMEOUT(),
4219 &request
, NULL
, NULL
);
4224 ctdb_req_control_wipe_database(&request
, &wipedb
);
4225 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4226 pnn_list
, count
, TIMEOUT(),
4227 &request
, NULL
, NULL
);
4232 pulldb
.db_id
= ctdb_db_id(db
);
4234 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4236 ctdb_req_control_db_push_start(&request
, &pulldb
);
4237 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4238 pnn_list
, count
, TIMEOUT(),
4239 &request
, NULL
, NULL
);
4244 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4245 struct ctdb_req_message message
;
4249 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4254 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4255 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4256 if (data
.dptr
== NULL
) {
4260 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4262 message
.srvid
= pulldb
.srvid
;
4263 message
.data
.data
= data
;
4265 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4273 talloc_free(recbuf
);
4274 talloc_free(data
.dptr
);
4277 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4278 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4279 pnn_list
, count
, TIMEOUT(),
4280 &request
, NULL
, &reply
);
4285 for (i
=0; i
<count
; i
++) {
4286 uint32_t num_records
;
4288 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4291 fprintf(stderr
, "Invalid response from node %u\n",
4296 if (num_records
!= db_hdr
.nrec
) {
4297 fprintf(stderr
, "Node %u received %u of %lu records\n",
4298 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4303 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4304 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4305 pnn_list
, count
, TIMEOUT(),
4306 &request
, NULL
, NULL
);
4311 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4312 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4313 pnn_list
, count
, TIMEOUT(),
4314 &request
, NULL
, NULL
);
4319 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4320 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4321 ctdb
->client
, pnn_list
, count
,
4322 TIMEOUT(), &request
, NULL
, NULL
);
4327 printf("Database %s restored\n", db_name
);
4334 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4335 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4339 struct dumpdbbackup_state
{
4340 ctdb_rec_parser_func_t parser
;
4341 struct dump_record_state sub_state
;
4344 static int dumpdbbackup_handler(uint32_t reqid
,
4345 struct ctdb_ltdb_header
*header
,
4346 TDB_DATA key
, TDB_DATA data
,
4349 struct dumpdbbackup_state
*state
=
4350 (struct dumpdbbackup_state
*)private_data
;
4351 struct ctdb_ltdb_header hdr
;
4354 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4359 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4362 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4363 int argc
, const char **argv
)
4365 struct db_header db_hdr
;
4367 struct dumpdbbackup_state state
;
4372 usage("dumpbackup");
4375 fd
= open(argv
[0], O_RDONLY
, 0600);
4378 fprintf(stderr
, "Failed to open file %s for reading\n",
4383 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4387 fprintf(stderr
, "Failed to read db header from file %s\n",
4391 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4393 if (db_hdr
.version
!= DB_VERSION
) {
4395 "Wrong version of backup file, expected %u, got %lu\n",
4396 DB_VERSION
, db_hdr
.version
);
4401 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4402 localtime(&db_hdr
.timestamp
));
4403 printf("Dumping database %s from backup @ %s\n",
4404 db_hdr
.name
, timebuf
);
4406 state
.parser
= dump_record
;
4407 state
.sub_state
.count
= 0;
4409 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4410 struct ctdb_rec_buffer
*recbuf
;
4412 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4414 fprintf(stderr
, "Failed to read records\n");
4419 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4422 fprintf(stderr
, "Failed to dump records\n");
4429 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4433 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4434 int argc
, const char **argv
)
4436 const char *db_name
;
4437 struct ctdb_db_context
*db
;
4440 struct ctdb_node_map
*nodemap
;
4441 struct ctdb_req_control request
;
4442 struct ctdb_transdb wipedb
;
4443 uint32_t generation
;
4451 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4455 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4458 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4462 nodemap
= get_nodemap(ctdb
, false);
4463 if (nodemap
== NULL
) {
4464 fprintf(stderr
, "Failed to get nodemap\n");
4468 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4470 fprintf(stderr
, "Failed to get current generation\n");
4474 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4480 ctdb_req_control_db_freeze(&request
, db_id
);
4481 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4482 ctdb
->client
, pnn_list
, count
,
4483 TIMEOUT(), &request
, NULL
, NULL
);
4488 wipedb
.db_id
= db_id
;
4489 wipedb
.tid
= generation
;
4491 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4492 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4493 pnn_list
, count
, TIMEOUT(),
4494 &request
, NULL
, NULL
);
4499 ctdb_req_control_wipe_database(&request
, &wipedb
);
4500 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4501 pnn_list
, count
, TIMEOUT(),
4502 &request
, NULL
, NULL
);
4507 ctdb_req_control_db_set_healthy(&request
, db_id
);
4508 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4509 pnn_list
, count
, TIMEOUT(),
4510 &request
, NULL
, NULL
);
4515 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4516 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4517 pnn_list
, count
, TIMEOUT(),
4518 &request
, NULL
, NULL
);
4523 ctdb_req_control_db_thaw(&request
, db_id
);
4524 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4525 ctdb
->client
, pnn_list
, count
,
4526 TIMEOUT(), &request
, NULL
, NULL
);
4531 printf("Database %s wiped\n", db_name
);
4536 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4537 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4541 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4542 int argc
, const char **argv
)
4547 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4548 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4553 printf("%u\n", recmaster
);
4557 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4558 int argc
, const char **argv
)
4560 char *t
, *event_helper
= NULL
;
4561 char *eventd_socket
= NULL
;
4562 const char **new_argv
;
4565 t
= getenv("CTDB_EVENT_HELPER");
4567 event_helper
= talloc_strdup(mem_ctx
, t
);
4569 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_event",
4570 CTDB_HELPER_BINDIR
);
4573 if (event_helper
== NULL
) {
4574 fprintf(stderr
, "Unable to set event daemon helper\n");
4578 t
= getenv("CTDB_SOCKET");
4580 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4583 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4587 if (eventd_socket
== NULL
) {
4588 fprintf(stderr
, "Unable to set event daemon socket\n");
4592 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 1);
4593 if (new_argv
== NULL
) {
4594 fprintf(stderr
, "Memory allocation error\n");
4598 new_argv
[0] = eventd_socket
;
4599 for (i
=0; i
<argc
; i
++) {
4600 new_argv
[i
+1] = argv
[i
];
4603 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4607 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4608 int argc
, const char **argv
)
4610 const char *new_argv
[3];
4613 usage("scriptstatus");
4616 new_argv
[0] = "status";
4617 new_argv
[1] = (argc
== 0) ? "monitor" : argv
[0];
4620 (void) control_event(mem_ctx
, ctdb
, 2, new_argv
);
4624 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4625 int argc
, const char **argv
)
4627 char *t
, *natgw_helper
= NULL
;
4633 t
= getenv("CTDB_NATGW_HELPER");
4635 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4637 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4638 CTDB_HELPER_BINDIR
);
4641 if (natgw_helper
== NULL
) {
4642 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4646 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4651 * Find the PNN of the current node
4652 * discover the pnn by loading the nodes file and try to bind
4653 * to all addresses one at a time until the ip address is found.
4655 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4657 struct ctdb_node_map
*nodemap
;
4660 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4661 if (nodemap
== NULL
) {
4665 for (i
=0; i
<nodemap
->num
; i
++) {
4666 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4669 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4671 *pnn
= nodemap
->node
[i
].pnn
;
4673 talloc_free(nodemap
);
4678 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4679 talloc_free(nodemap
);
4683 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4684 int argc
, const char **argv
)
4686 const char *reclock
;
4690 usage("getreclock");
4693 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4694 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4699 if (reclock
!= NULL
) {
4700 printf("%s\n", reclock
);
4706 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4707 struct ctdb_context
*ctdb
,
4708 int argc
, const char **argv
)
4710 uint32_t lmasterrole
= 0;
4714 usage("setlmasterrole");
4717 if (strcmp(argv
[0], "on") == 0) {
4719 } else if (strcmp(argv
[0], "off") == 0) {
4722 usage("setlmasterrole");
4725 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4726 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4734 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4735 struct ctdb_context
*ctdb
,
4736 int argc
, const char **argv
)
4738 uint32_t recmasterrole
= 0;
4742 usage("setrecmasterrole");
4745 if (strcmp(argv
[0], "on") == 0) {
4747 } else if (strcmp(argv
[0], "off") == 0) {
4750 usage("setrecmasterrole");
4753 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4754 ctdb
->cmd_pnn
, TIMEOUT(),
4763 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4764 struct ctdb_context
*ctdb
,
4765 int argc
, const char **argv
)
4772 usage("setdbreadonly");
4775 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4779 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4780 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4784 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4785 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4793 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4794 int argc
, const char **argv
)
4801 usage("setdbsticky");
4804 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4808 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4809 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4813 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4814 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4822 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4823 int argc
, const char **argv
)
4825 const char *db_name
;
4826 struct ctdb_db_context
*db
;
4827 struct ctdb_transaction_handle
*h
;
4832 if (argc
< 2 || argc
> 3) {
4836 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4841 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4842 fprintf(stderr
, "Transactions not supported on DB %s\n",
4847 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4850 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4854 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4856 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4860 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4861 TIMEOUT(), db
, true, &h
);
4863 fprintf(stderr
, "Failed to start transaction on db %s\n",
4868 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4870 fprintf(stderr
, "Failed to read record for key %s\n",
4872 ctdb_transaction_cancel(h
);
4876 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4878 ctdb_transaction_cancel(h
);
4882 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4883 int argc
, const char **argv
)
4885 const char *db_name
;
4886 struct ctdb_db_context
*db
;
4887 struct ctdb_transaction_handle
*h
;
4896 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4901 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4902 fprintf(stderr
, "Transactions not supported on DB %s\n",
4907 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4910 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4914 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4916 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4920 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4922 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
4926 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4927 TIMEOUT(), db
, false, &h
);
4929 fprintf(stderr
, "Failed to start transaction on db %s\n",
4934 ret
= ctdb_transaction_store_record(h
, key
, data
);
4936 fprintf(stderr
, "Failed to store record for key %s\n",
4938 ctdb_transaction_cancel(h
);
4942 ret
= ctdb_transaction_commit(h
);
4944 fprintf(stderr
, "Failed to commit transaction on db %s\n",
4946 ctdb_transaction_cancel(h
);
4953 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4954 int argc
, const char **argv
)
4956 const char *db_name
;
4957 struct ctdb_db_context
*db
;
4958 struct ctdb_transaction_handle
*h
;
4967 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4972 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4973 fprintf(stderr
, "Transactions not supported on DB %s\n",
4978 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4981 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4985 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4987 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4991 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4992 TIMEOUT(), db
, false, &h
);
4994 fprintf(stderr
, "Failed to start transaction on db %s\n",
4999 ret
= ctdb_transaction_delete_record(h
, key
);
5001 fprintf(stderr
, "Failed to delete record for key %s\n",
5003 ctdb_transaction_cancel(h
);
5007 ret
= ctdb_transaction_commit(h
);
5009 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5011 ctdb_transaction_cancel(h
);
5018 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5026 /* Skip whitespace */
5027 n
= strspn(*ptr
, " \t");
5031 /* Quoted ASCII string - no wide characters! */
5033 n
= strcspn(t
, "\"");
5036 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5043 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5047 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5054 #define MAX_LINE_SIZE 1024
5056 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5057 TDB_DATA
*key
, TDB_DATA
*value
)
5059 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5063 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5069 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5070 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5071 /* Line Ignored but not EOF */
5077 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5079 /* Line Ignored but not EOF */
5080 talloc_free(key
->dptr
);
5088 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5089 int argc
, const char **argv
)
5091 const char *db_name
;
5092 struct ctdb_db_context
*db
;
5093 struct ctdb_transaction_handle
*h
;
5096 TDB_DATA key
, value
;
5099 if (argc
< 1 || argc
> 2) {
5103 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5108 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5109 fprintf(stderr
, "Transactions not supported on DB %s\n",
5115 file
= fopen(argv
[1], "r");
5117 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5124 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5127 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5131 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5132 TIMEOUT(), db
, false, &h
);
5134 fprintf(stderr
, "Failed to start transaction on db %s\n",
5139 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5140 if (key
.dsize
!= 0) {
5141 ret
= ctdb_transaction_store_record(h
, key
, value
);
5143 fprintf(stderr
, "Failed to store record\n");
5144 ctdb_transaction_cancel(h
);
5147 talloc_free(key
.dptr
);
5148 talloc_free(value
.dptr
);
5152 ret
= ctdb_transaction_commit(h
);
5154 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5156 ctdb_transaction_cancel(h
);
5160 if (file
!= stdin
) {
5166 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5167 int argc
, const char **argv
)
5169 struct tdb_context
*tdb
;
5171 struct ctdb_ltdb_header header
;
5174 if (argc
< 2 || argc
> 3) {
5178 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5180 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5184 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5186 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5191 data
= tdb_fetch(tdb
, key
);
5192 if (data
.dptr
== NULL
) {
5193 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5198 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5199 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5210 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5212 fprintf(stderr
, "Failed to open output file %s\n",
5217 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5218 if (nwritten
!= data
.dsize
) {
5219 fprintf(stderr
, "Failed to write record to file\n");
5228 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5230 fprintf(stderr
, "Failed to parse header from data\n");
5234 dump_ltdb_header(&header
);
5235 dump_tdb_data("data", data
);
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
)];
5250 if (argc
< 3 || argc
> 5) {
5254 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5256 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5260 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5262 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5267 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5269 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5274 ZERO_STRUCT(header
);
5277 header
.rsn
= (uint64_t)strtoull(argv
[3], NULL
, 0);
5280 header
.dmaster
= (uint32_t)atol(argv
[4]);
5283 header
.flags
= (uint32_t)atol(argv
[5]);
5286 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5289 data
[0].dptr
= header_buf
;
5291 data
[1].dsize
= value
.dsize
;
5292 data
[1].dptr
= value
.dptr
;
5294 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5296 fprintf(stderr
, "Failed to write record %s to file %s\n",
5305 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5306 int argc
, const char **argv
)
5308 const char *db_name
;
5309 struct ctdb_db_context
*db
;
5310 struct ctdb_record_handle
*h
;
5313 bool readonly
= false;
5316 if (argc
< 2 || argc
> 3) {
5321 if (strcmp(argv
[2], "readonly") == 0) {
5328 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5332 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5333 fprintf(stderr
, "DB %s is not a volatile database\n",
5338 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5341 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5345 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5347 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5351 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5352 db
, key
, readonly
, &h
, NULL
, &data
);
5354 fprintf(stderr
, "Failed to read record for key %s\n",
5357 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5358 (int)data
.dsize
, data
.dptr
);
5365 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5366 int argc
, const char **argv
)
5368 const char *db_name
;
5369 struct ctdb_db_context
*db
;
5370 struct ctdb_record_handle
*h
;
5379 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5383 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5384 fprintf(stderr
, "DB %s is not a volatile database\n",
5389 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5392 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5396 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5398 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5402 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5404 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5408 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5409 db
, key
, false, &h
, NULL
, NULL
);
5411 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5415 ret
= ctdb_store_record(h
, data
);
5417 fprintf(stderr
, "Failed to store record for key %s\n",
5425 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5426 int argc
, const char **argv
)
5428 const char *db_name
;
5429 struct ctdb_db_context
*db
;
5430 struct ctdb_record_handle
*h
;
5439 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5443 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5444 fprintf(stderr
, "DB %s is not a volatile database\n",
5449 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5452 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5456 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5458 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5462 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5463 db
, key
, false, &h
, NULL
, &data
);
5465 fprintf(stderr
, "Failed to fetch record for key %s\n",
5470 ret
= ctdb_delete_record(h
);
5472 fprintf(stderr
, "Failed to delete record for key %s\n",
5480 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5481 int argc
, const char **argv
)
5483 struct sockaddr_in sin
;
5489 usage("chktcpport");
5492 port
= atoi(argv
[0]);
5494 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5496 fprintf(stderr
, "Failed to open local socket\n");
5500 v
= fcntl(s
, F_GETFL
, 0);
5501 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5502 fprintf(stderr
, "Unable to set socket non-blocking\n");
5507 bzero(&sin
, sizeof(sin
));
5508 sin
.sin_family
= AF_INET
;
5509 sin
.sin_port
= htons(port
);
5510 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5513 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5520 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5521 int argc
, const char **argv
)
5524 const char *db_name
;
5529 usage("getdbseqnum");
5532 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5536 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5537 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5540 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5545 printf("0x%"PRIx64
"\n", seqnum
);
5549 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5550 int argc
, const char **argv
)
5552 const char *nodestring
= NULL
;
5553 struct ctdb_node_map
*nodemap
;
5555 bool print_hdr
= false;
5558 usage("nodestatus");
5562 nodestring
= argv
[0];
5563 if (strcmp(nodestring
, "all") == 0) {
5568 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5572 if (options
.machinereadable
) {
5573 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5575 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5579 for (i
=0; i
<nodemap
->num
; i
++) {
5580 ret
|= nodemap
->node
[i
].flags
;
5589 } db_stats_fields
[] = {
5590 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5591 DBSTATISTICS_FIELD(db_ro_delegations
),
5592 DBSTATISTICS_FIELD(db_ro_revokes
),
5593 DBSTATISTICS_FIELD(locks
.num_calls
),
5594 DBSTATISTICS_FIELD(locks
.num_current
),
5595 DBSTATISTICS_FIELD(locks
.num_pending
),
5596 DBSTATISTICS_FIELD(locks
.num_failed
),
5599 static void print_dbstatistics(const char *db_name
,
5600 struct ctdb_db_statistics
*s
)
5603 const char *prefix
= NULL
;
5606 printf("DB Statistics %s\n", db_name
);
5608 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5609 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5610 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5612 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5613 prefix
= db_stats_fields
[i
].name
;
5614 printf(" %*.*s\n", preflen
-1, preflen
-1,
5615 db_stats_fields
[i
].name
);
5620 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5621 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5622 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5625 printf(" hop_count_buckets:");
5626 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5627 printf(" %d", s
->hop_count_bucket
[i
]);
5631 printf(" lock_buckets:");
5632 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5633 printf(" %d", s
->locks
.buckets
[i
]);
5637 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5638 "locks_latency MIN/AVG/MAX",
5639 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5640 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5642 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5643 "vacuum_latency MIN/AVG/MAX",
5644 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5645 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5647 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5648 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5650 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5651 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5652 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5658 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5659 int argc
, const char **argv
)
5662 const char *db_name
;
5663 struct ctdb_db_statistics
*dbstats
;
5667 usage("dbstatistics");
5670 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5674 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5675 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5678 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5683 print_dbstatistics(db_name
, dbstats
);
5687 struct disable_takeover_runs_state
{
5695 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5698 struct disable_takeover_runs_state
*state
=
5699 (struct disable_takeover_runs_state
*)private_data
;
5702 if (data
.dsize
!= sizeof(int)) {
5707 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5708 ret
= *(int *)data
.dptr
;
5710 state
->status
= ret
;
5714 for (i
=0; i
<state
->node_count
; i
++) {
5715 if (state
->pnn_list
[i
] == ret
) {
5716 state
->reply
[i
] = true;
5722 for (i
=0; i
<state
->node_count
; i
++) {
5723 if (! state
->reply
[i
]) {
5724 state
->done
= false;
5730 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5731 struct ctdb_context
*ctdb
, uint32_t timeout
,
5732 uint32_t *pnn_list
, int count
)
5734 struct ctdb_disable_message disable
= { 0 };
5735 struct disable_takeover_runs_state state
;
5738 disable
.pnn
= ctdb
->pnn
;
5739 disable
.srvid
= next_srvid(ctdb
);
5740 disable
.timeout
= timeout
;
5742 state
.pnn_list
= pnn_list
;
5743 state
.node_count
= count
;
5746 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5747 if (state
.reply
== NULL
) {
5751 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5753 disable_takeover_run_handler
,
5759 for (i
=0; i
<count
; i
++) {
5760 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5769 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5771 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5773 ret
= (state
.status
>= 0 ? 0 : 1);
5777 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5778 disable
.srvid
, &state
);
5782 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5783 int argc
, const char **argv
)
5785 const char *nodestring
= NULL
;
5786 struct ctdb_node_map
*nodemap
, *nodemap2
;
5787 struct ctdb_req_control request
;
5788 uint32_t *pnn_list
, *pnn_list2
;
5789 int ret
, count
, count2
;
5796 nodestring
= argv
[0];
5799 nodemap
= get_nodemap(ctdb
, false);
5800 if (nodemap
== NULL
) {
5804 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5808 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5809 mem_ctx
, &pnn_list
);
5811 fprintf(stderr
, "Memory allocation error\n");
5815 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5816 mem_ctx
, &pnn_list2
);
5818 fprintf(stderr
, "Memory allocation error\n");
5822 /* Disable takeover runs on all connected nodes. A reply
5823 * indicating success is needed from each node so all nodes
5824 * will need to be active.
5826 * A check could be added to not allow reloading of IPs when
5827 * there are disconnected nodes. However, this should
5828 * probably be left up to the administrator.
5830 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5833 fprintf(stderr
, "Failed to disable takeover runs\n");
5837 /* Now tell all the desired nodes to reload their public IPs.
5838 * Keep trying this until it succeeds. This assumes all
5839 * failures are transient, which might not be true...
5841 ctdb_req_control_reload_public_ips(&request
);
5842 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5843 pnn_list2
, count2
, TIMEOUT(),
5844 &request
, NULL
, NULL
);
5846 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5849 /* It isn't strictly necessary to wait until takeover runs are
5850 * re-enabled but doing so can't hurt.
5852 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5854 fprintf(stderr
, "Failed to enable takeover runs\n");
5858 return ipreallocate(mem_ctx
, ctdb
);
5862 static const struct ctdb_cmd
{
5864 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5865 bool without_daemon
; /* can be run without daemon running ? */
5866 bool remote
; /* can be run on remote nodes */
5869 } ctdb_commands
[] = {
5870 { "version", control_version
, true, false,
5871 "show version of ctdb", NULL
},
5872 { "status", control_status
, false, true,
5873 "show node status", NULL
},
5874 { "uptime", control_uptime
, false, true,
5875 "show node uptime", NULL
},
5876 { "ping", control_ping
, false, true,
5877 "ping a node", NULL
},
5878 { "runstate", control_runstate
, false, true,
5879 "get/check runstate of a node",
5880 "[setup|first_recovery|startup|running]" },
5881 { "getvar", control_getvar
, false, true,
5882 "get a tunable variable", "<name>" },
5883 { "setvar", control_setvar
, false, true,
5884 "set a tunable variable", "<name> <value>" },
5885 { "listvars", control_listvars
, false, true,
5886 "list tunable variables", NULL
},
5887 { "statistics", control_statistics
, false, true,
5888 "show ctdb statistics", NULL
},
5889 { "statisticsreset", control_statistics_reset
, false, true,
5890 "reset ctdb statistics", NULL
},
5891 { "stats", control_stats
, false, true,
5892 "show rolling statistics", "[count]" },
5893 { "ip", control_ip
, false, true,
5894 "show public ips", "[all]" },
5895 { "ipinfo", control_ipinfo
, false, true,
5896 "show public ip details", "<ip>" },
5897 { "ifaces", control_ifaces
, false, true,
5898 "show interfaces", NULL
},
5899 { "setifacelink", control_setifacelink
, false, true,
5900 "set interface link status", "<iface> up|down" },
5901 { "process-exists", control_process_exists
, false, true,
5902 "check if a process exists on a node", "<pid> [<srvid>]" },
5903 { "getdbmap", control_getdbmap
, false, true,
5904 "show attached databases", NULL
},
5905 { "getdbstatus", control_getdbstatus
, false, true,
5906 "show database status", "<dbname|dbid>" },
5907 { "catdb", control_catdb
, false, false,
5908 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5909 { "cattdb", control_cattdb
, false, false,
5910 "dump local ctdb database", "<dbname|dbid>" },
5911 { "getcapabilities", control_getcapabilities
, false, true,
5912 "show node capabilities", NULL
},
5913 { "pnn", control_pnn
, false, false,
5914 "show the pnn of the currnet node", NULL
},
5915 { "lvs", control_lvs
, false, false,
5916 "show lvs configuration", "master|list|status" },
5917 { "setdebug", control_setdebug
, false, true,
5918 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5919 { "getdebug", control_getdebug
, false, true,
5920 "get debug level", NULL
},
5921 { "attach", control_attach
, false, false,
5922 "attach a database", "<dbname> [persistent|replicated]" },
5923 { "detach", control_detach
, false, false,
5924 "detach database(s)", "<dbname|dbid> ..." },
5925 { "dumpmemory", control_dumpmemory
, false, true,
5926 "dump ctdbd memory map", NULL
},
5927 { "rddumpmemory", control_rddumpmemory
, false, true,
5928 "dump recoverd memory map", NULL
},
5929 { "getpid", control_getpid
, false, true,
5930 "get ctdbd process ID", NULL
},
5931 { "disable", control_disable
, false, true,
5932 "disable a node", NULL
},
5933 { "enable", control_enable
, false, true,
5934 "enable a node", NULL
},
5935 { "stop", control_stop
, false, true,
5936 "stop a node", NULL
},
5937 { "continue", control_continue
, false, true,
5938 "continue a stopped node", NULL
},
5939 { "ban", control_ban
, false, true,
5940 "ban a node", "<bantime>"},
5941 { "unban", control_unban
, false, true,
5942 "unban a node", NULL
},
5943 { "shutdown", control_shutdown
, false, true,
5944 "shutdown ctdb daemon", NULL
},
5945 { "recover", control_recover
, false, true,
5946 "force recovery", NULL
},
5947 { "sync", control_ipreallocate
, false, true,
5948 "run ip reallocation (deprecated)", NULL
},
5949 { "ipreallocate", control_ipreallocate
, false, true,
5950 "run ip reallocation", NULL
},
5951 { "isnotrecmaster", control_isnotrecmaster
, false, false,
5952 "check if local node is the recmaster", NULL
},
5953 { "gratarp", control_gratarp
, false, true,
5954 "send a gratuitous arp", "<ip> <interface>" },
5955 { "tickle", control_tickle
, true, false,
5956 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5957 { "gettickles", control_gettickles
, false, true,
5958 "get the list of tickles", "<ip> [<port>]" },
5959 { "addtickle", control_addtickle
, false, true,
5960 "add a tickle", "<ip>:<port> <ip>:<port>" },
5961 { "deltickle", control_deltickle
, false, true,
5962 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5963 { "listnodes", control_listnodes
, true, true,
5964 "list nodes in the cluster", NULL
},
5965 { "reloadnodes", control_reloadnodes
, false, false,
5966 "reload the nodes file all nodes", NULL
},
5967 { "moveip", control_moveip
, false, false,
5968 "move an ip address to another node", "<ip> <node>" },
5969 { "addip", control_addip
, false, true,
5970 "add an ip address to a node", "<ip/mask> <iface>" },
5971 { "delip", control_delip
, false, true,
5972 "delete an ip address from a node", "<ip>" },
5973 { "backupdb", control_backupdb
, false, false,
5974 "backup a database into a file", "<dbname|dbid> <file>" },
5975 { "restoredb", control_restoredb
, false, false,
5976 "restore a database from a file", "<file> [dbname]" },
5977 { "dumpdbbackup", control_dumpdbbackup
, true, false,
5978 "dump database from a backup file", "<file>" },
5979 { "wipedb", control_wipedb
, false, false,
5980 "wipe the contents of a database.", "<dbname|dbid>"},
5981 { "recmaster", control_recmaster
, false, true,
5982 "show the pnn for the recovery master", NULL
},
5983 { "event", control_event
, false, false,
5984 "event and event script commands", NULL
},
5985 { "scriptstatus", control_scriptstatus
, false, false,
5986 "show event script status",
5987 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5988 { "natgw", control_natgw
, false, false,
5989 "show natgw configuration", "master|list|status" },
5990 { "getreclock", control_getreclock
, false, true,
5991 "get recovery lock file", NULL
},
5992 { "setlmasterrole", control_setlmasterrole
, false, true,
5993 "set LMASTER role", "on|off" },
5994 { "setrecmasterrole", control_setrecmasterrole
, false, true,
5995 "set RECMASTER role", "on|off"},
5996 { "setdbreadonly", control_setdbreadonly
, false, true,
5997 "enable readonly records", "<dbname|dbid>" },
5998 { "setdbsticky", control_setdbsticky
, false, true,
5999 "enable sticky records", "<dbname|dbid>"},
6000 { "pfetch", control_pfetch
, false, false,
6001 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6002 { "pstore", control_pstore
, false, false,
6003 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6004 { "pdelete", control_pdelete
, false, false,
6005 "delete record from persistent database", "<dbname|dbid> <key>" },
6006 { "ptrans", control_ptrans
, false, false,
6007 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6008 { "tfetch", control_tfetch
, false, true,
6009 "fetch a record", "<tdb-file> <key> [<file>]" },
6010 { "tstore", control_tstore
, false, true,
6011 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6012 { "readkey", control_readkey
, false, false,
6013 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6014 { "writekey", control_writekey
, false, false,
6015 "write value for a database key", "<dbname|dbid> <key> <value>" },
6016 { "deletekey", control_deletekey
, false, false,
6017 "delete a database key", "<dbname|dbid> <key>" },
6018 { "checktcpport", control_checktcpport
, true, false,
6019 "check if a service is bound to a specific tcp port or not", "<port>" },
6020 { "getdbseqnum", control_getdbseqnum
, false, false,
6021 "get database sequence number", "<dbname|dbid>" },
6022 { "nodestatus", control_nodestatus
, false, true,
6023 "show and return node status", "[all|<pnn-list>]" },
6024 { "dbstatistics", control_dbstatistics
, false, true,
6025 "show database statistics", "<dbname|dbid>" },
6026 { "reloadips", control_reloadips
, false, false,
6027 "reload the public addresses file", "[all|<pnn-list>]" },
6030 static const struct ctdb_cmd
*match_command(const char *command
)
6032 const struct ctdb_cmd
*cmd
;
6035 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6036 cmd
= &ctdb_commands
[i
];
6037 if (strlen(command
) == strlen(cmd
->name
) &&
6038 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6048 * Show usage message
6050 static void usage_full(void)
6054 poptPrintHelp(pc
, stdout
, 0);
6055 printf("\nCommands:\n");
6056 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6057 printf(" %-15s %-27s %s\n",
6058 ctdb_commands
[i
].name
,
6059 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6060 ctdb_commands
[i
].msg
);
6064 static void usage(const char *command
)
6066 const struct ctdb_cmd
*cmd
;
6068 if (command
== NULL
) {
6073 cmd
= match_command(command
);
6077 poptPrintUsage(pc
, stdout
, 0);
6078 printf("\nCommands:\n");
6079 printf(" %-15s %-27s %s\n",
6080 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6086 struct poptOption cmdline_options
[] = {
6088 { "debug", 'd', POPT_ARG_STRING
, &options
.debuglevelstr
, 0,
6090 { "timelimit", 't', POPT_ARG_INT
, &options
.timelimit
, 0,
6091 "timelimit (in seconds)" },
6092 { "node", 'n', POPT_ARG_INT
, &options
.pnn
, 0,
6093 "node specification - integer" },
6094 { NULL
, 'Y', POPT_ARG_NONE
, &options
.machinereadable
, 0,
6095 "enable machine readable output", NULL
},
6096 { "separator", 'x', POPT_ARG_STRING
, &options
.sep
, 0,
6097 "specify separator for machine readable output", "CHAR" },
6098 { NULL
, 'X', POPT_ARG_NONE
, &options
.machineparsable
, 0,
6099 "enable machine parsable output with separator |", NULL
},
6100 { "verbose", 'v', POPT_ARG_NONE
, &options
.verbose
, 0,
6101 "enable verbose output", NULL
},
6102 { "maxruntime", 'T', POPT_ARG_INT
, &options
.maxruntime
, 0,
6103 "die if runtime exceeds this limit (in seconds)" },
6107 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6110 TALLOC_CTX
*tmp_ctx
;
6111 struct ctdb_context
*ctdb
;
6112 const char *ctdb_socket
;
6115 uint64_t srvid_offset
;
6117 tmp_ctx
= talloc_new(NULL
);
6118 if (tmp_ctx
== NULL
) {
6119 fprintf(stderr
, "Memory allocation error\n");
6123 if (cmd
->without_daemon
) {
6124 if (options
.pnn
!= -1) {
6126 "Cannot specify node for command %s\n",
6131 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6132 talloc_free(tmp_ctx
);
6136 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6138 fprintf(stderr
, "Memory allocation error\n");
6142 ctdb
->ev
= tevent_context_init(ctdb
);
6143 if (ctdb
->ev
== NULL
) {
6144 fprintf(stderr
, "Failed to initialize tevent\n");
6148 ctdb_socket
= getenv("CTDB_SOCKET");
6149 if (ctdb_socket
== NULL
) {
6150 ctdb_socket
= CTDB_SOCKET
;
6153 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6155 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6158 if (!find_node_xpnn(ctdb
, NULL
)) {
6159 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6164 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6165 srvid_offset
= getpid() & 0xFFFF;
6166 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6168 if (options
.pnn
!= -1) {
6169 status
= verify_pnn(ctdb
, options
.pnn
);
6174 ctdb
->cmd_pnn
= options
.pnn
;
6176 ctdb
->cmd_pnn
= ctdb
->pnn
;
6179 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6180 fprintf(stderr
, "Node cannot be specified for command %s\n",
6185 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6186 talloc_free(tmp_ctx
);
6190 talloc_free(tmp_ctx
);
6194 static void signal_handler(int sig
)
6196 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6199 static void alarm_handler(int sig
)
6201 /* Kill any child processes */
6202 signal(SIGTERM
, signal_handler
);
6208 int main(int argc
, const char *argv
[])
6211 const char **extra_argv
;
6213 const struct ctdb_cmd
*cmd
;
6219 /* Set default options */
6220 options
.debuglevelstr
= NULL
;
6221 options
.timelimit
= 10;
6223 options
.maxruntime
= 0;
6226 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6227 POPT_CONTEXT_KEEP_FIRST
);
6228 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6229 fprintf(stderr
, "Invalid option %s: %s\n",
6230 poptBadOption(pc
, 0), poptStrerror(opt
));
6234 if (options
.maxruntime
== 0) {
6235 const char *ctdb_timeout
;
6237 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6238 if (ctdb_timeout
!= NULL
) {
6239 options
.maxruntime
= strtoul(ctdb_timeout
, NULL
, 0);
6241 options
.maxruntime
= 120;
6244 if (options
.maxruntime
<= 120) {
6245 /* default timeout is 120 seconds */
6246 options
.maxruntime
= 120;
6249 if (options
.machineparsable
) {
6250 options
.machinereadable
= 1;
6253 /* setup the remaining options for the commands */
6255 extra_argv
= poptGetArgs(pc
);
6258 while (extra_argv
[extra_argc
]) extra_argc
++;
6261 if (extra_argc
< 1) {
6265 cmd
= match_command(extra_argv
[0]);
6267 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6271 /* Enable logging */
6272 setup_logging("ctdb", DEBUG_STDERR
);
6273 if (debug_level_parse(options
.debuglevelstr
, &loglevel
)) {
6274 DEBUGLEVEL
= loglevel
;
6276 DEBUGLEVEL
= DEBUG_ERR
;
6279 signal(SIGALRM
, alarm_handler
);
6280 alarm(options
.maxruntime
);
6282 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6287 (void)poptFreeContext(pc
);