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 "common/path.h"
41 #include "protocol/protocol.h"
42 #include "protocol/protocol_api.h"
43 #include "protocol/protocol_util.h"
44 #include "common/system_socket.h"
45 #include "client/client.h"
46 #include "client/client_sync.h"
48 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
50 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
51 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
54 const char *debuglevelstr
;
62 int printemptyrecords
;
69 static poptContext pc
;
72 struct tevent_context
*ev
;
73 struct ctdb_client_context
*client
;
74 struct ctdb_node_map
*nodemap
;
75 uint32_t pnn
, cmd_pnn
;
79 static void usage(const char *command
);
85 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
87 return (tv2
->tv_sec
- tv
->tv_sec
) +
88 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
91 static struct ctdb_node_and_flags
*get_node_by_pnn(
92 struct ctdb_node_map
*nodemap
,
97 for (i
=0; i
<nodemap
->num
; i
++) {
98 if (nodemap
->node
[i
].pnn
== pnn
) {
99 return &nodemap
->node
[i
];
105 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
107 static const struct {
111 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
112 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
113 { NODE_FLAGS_BANNED
, "BANNED" },
114 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
115 { NODE_FLAGS_DELETED
, "DELETED" },
116 { NODE_FLAGS_STOPPED
, "STOPPED" },
117 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
119 char *flags_str
= NULL
;
122 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
123 if (flags
& flag_names
[i
].flag
) {
124 if (flags_str
== NULL
) {
125 flags_str
= talloc_asprintf(mem_ctx
,
126 "%s", flag_names
[i
].name
);
128 flags_str
= talloc_asprintf_append(flags_str
,
129 "|%s", flag_names
[i
].name
);
131 if (flags_str
== NULL
) {
132 return "OUT-OF-MEMORY";
136 if (flags_str
== NULL
) {
143 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
150 * Get consistent nodemap information.
152 * If nodemap is already cached, use that. If not get it.
153 * If the current node is BANNED, then get nodemap from "better" node.
155 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
158 struct ctdb_node_map
*nodemap
;
159 struct ctdb_node_and_flags
*node
;
160 uint32_t current_node
;
164 TALLOC_FREE(ctdb
->nodemap
);
167 if (ctdb
->nodemap
!= NULL
) {
168 return ctdb
->nodemap
;
171 tmp_ctx
= talloc_new(ctdb
);
172 if (tmp_ctx
== NULL
) {
176 current_node
= ctdb
->pnn
;
178 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
179 current_node
, TIMEOUT(), &nodemap
);
181 fprintf(stderr
, "Failed to get nodemap from node %u\n",
186 node
= get_node_by_pnn(nodemap
, current_node
);
187 if (node
->flags
& NODE_FLAGS_BANNED
) {
190 current_node
= (current_node
+ 1) % nodemap
->num
;
191 node
= get_node_by_pnn(nodemap
, current_node
);
193 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
196 } while (current_node
!= ctdb
->pnn
);
198 if (current_node
== ctdb
->pnn
) {
199 /* Tried all nodes in the cluster */
200 fprintf(stderr
, "Warning: All nodes are banned.\n");
207 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
211 talloc_free(tmp_ctx
);
215 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
217 struct ctdb_node_map
*nodemap
;
225 nodemap
= get_nodemap(ctdb
, false);
226 if (nodemap
== NULL
) {
231 for (i
=0; i
<nodemap
->num
; i
++) {
232 if (nodemap
->node
[i
].pnn
== pnn
) {
238 fprintf(stderr
, "Node %u does not exist\n", pnn
);
242 if (nodemap
->node
[i
].flags
&
243 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
244 fprintf(stderr
, "Node %u has status %s\n", pnn
,
245 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
252 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
253 struct ctdb_node_map
*nodemap
)
255 struct ctdb_node_map
*nodemap2
;
257 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
258 if (nodemap2
== NULL
) {
262 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
264 if (nodemap2
->node
== NULL
) {
265 talloc_free(nodemap2
);
273 * Get the number and the list of matching nodes
275 * nodestring := NULL | all | pnn,[pnn,...]
277 * If nodestring is NULL, use the current node.
279 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
280 const char *nodestring
,
281 struct ctdb_node_map
**out
)
283 struct ctdb_node_map
*nodemap
, *nodemap2
;
284 struct ctdb_node_and_flags
*node
;
287 nodemap
= get_nodemap(ctdb
, false);
288 if (nodemap
== NULL
) {
292 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
293 if (nodemap2
== NULL
) {
297 if (nodestring
== NULL
) {
298 for (i
=0; i
<nodemap
->num
; i
++) {
299 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
300 nodemap2
->node
[0] = nodemap
->node
[i
];
309 if (strcmp(nodestring
, "all") == 0) {
310 for (i
=0; i
<nodemap
->num
; i
++) {
311 nodemap2
->node
[i
] = nodemap
->node
[i
];
313 nodemap2
->num
= nodemap
->num
;
319 ns
= talloc_strdup(mem_ctx
, nodestring
);
324 tok
= strtok(ns
, ",");
325 while (tok
!= NULL
) {
329 pnn
= (uint32_t)strtoul(tok
, &endptr
, 0);
330 if (pnn
== 0 && tok
== endptr
) {
331 fprintf(stderr
, "Invalid node %s\n", tok
);
335 node
= get_node_by_pnn(nodemap
, pnn
);
337 fprintf(stderr
, "Node %u does not exist\n",
342 nodemap2
->node
[nodemap2
->num
] = *node
;
345 tok
= strtok(NULL
, ",");
354 /* Compare IP address */
355 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
359 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
363 switch (ip1
->sa
.sa_family
) {
365 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
366 sizeof(struct in_addr
)) == 0);
370 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
371 sizeof(struct in6_addr
)) == 0);
378 /* Append a node to a node map with given address and flags */
379 static bool node_map_add(struct ctdb_node_map
*nodemap
,
380 const char *nstr
, uint32_t flags
)
384 struct ctdb_node_and_flags
*n
;
387 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
389 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
394 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
395 struct ctdb_node_and_flags
, num
+1);
396 if (nodemap
->node
== NULL
) {
400 n
= &nodemap
->node
[num
];
405 nodemap
->num
= num
+1;
409 /* Read a nodes file into a node map */
410 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
416 struct ctdb_node_map
*nodemap
;
418 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
419 if (nodemap
== NULL
) {
423 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
428 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
432 for (i
=0; i
<nlines
; i
++) {
438 /* strip leading spaces */
439 while((*node
== ' ') || (*node
== '\t')) {
445 /* strip trailing spaces */
447 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
457 /* A "deleted" node is a node that is
458 commented out in the nodes file. This is
459 used instead of removing a line, which
460 would cause subsequent nodes to change
462 flags
= NODE_FLAGS_DELETED
;
463 node
= discard_const("0.0.0.0");
467 if (! node_map_add(nodemap
, node
, flags
)) {
469 TALLOC_FREE(nodemap
);
478 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
480 struct ctdb_node_map
*nodemap
;
481 const char *nodes_list
= NULL
;
483 const char *basedir
= getenv("CTDB_BASE");
484 if (basedir
== NULL
) {
485 basedir
= CTDB_ETCDIR
;
487 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
488 if (nodes_list
== NULL
) {
489 fprintf(stderr
, "Memory allocation error\n");
493 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
494 if (nodemap
== NULL
) {
495 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
503 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
504 struct ctdb_context
*ctdb
,
505 struct ctdb_dbid_map
*dbmap
,
508 struct ctdb_dbid
*db
= NULL
;
512 for (i
=0; i
<dbmap
->num
; i
++) {
513 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
514 ctdb
->pnn
, TIMEOUT(),
515 dbmap
->dbs
[i
].db_id
, &name
);
520 if (strcmp(db_name
, name
) == 0) {
521 talloc_free(discard_const(name
));
530 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
531 const char *db_arg
, uint32_t *db_id
,
532 const char **db_name
, uint8_t *db_flags
)
534 struct ctdb_dbid_map
*dbmap
;
535 struct ctdb_dbid
*db
= NULL
;
537 const char *name
= NULL
;
540 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
541 ctdb
->pnn
, TIMEOUT(), &dbmap
);
546 if (strncmp(db_arg
, "0x", 2) == 0) {
547 id
= strtoul(db_arg
, NULL
, 0);
548 for (i
=0; i
<dbmap
->num
; i
++) {
549 if (id
== dbmap
->dbs
[i
].db_id
) {
556 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
560 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
565 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
566 ctdb
->pnn
, TIMEOUT(), id
, &name
);
575 if (db_name
!= NULL
) {
576 *db_name
= talloc_strdup(mem_ctx
, name
);
578 if (db_flags
!= NULL
) {
579 *db_flags
= db
->flags
;
584 static int h2i(char h
)
586 if (h
>= 'a' && h
<= 'f') {
589 if (h
>= 'A' && h
<= 'F') {
595 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
602 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
607 data
.dsize
= len
/ 2;
608 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
609 if (data
.dptr
== NULL
) {
613 for (i
=0; i
<data
.dsize
; i
++) {
614 data
.dptr
[i
] = h2i(str
[i
*2]) << 4 | h2i(str
[i
*2+1]);
621 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
627 if (strncmp(str
, "0x", 2) == 0) {
628 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
633 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
634 if (data
.dptr
== NULL
) {
644 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
645 const char *path
, int argc
, const char **argv
)
648 int save_errno
, status
, ret
;
649 const char **new_argv
;
652 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
653 if (new_argv
== NULL
) {
658 for (i
=0; i
<argc
; i
++) {
659 new_argv
[i
+1] = argv
[i
];
661 new_argv
[argc
+1] = NULL
;
666 talloc_free(new_argv
);
667 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
668 command
, path
, strerror(save_errno
));
673 ret
= execv(path
, discard_const(new_argv
));
677 /* Should not happen */
681 talloc_free(new_argv
);
683 ret
= waitpid(pid
, &status
, 0);
686 fprintf(stderr
, "waitpid() failed for %s - %s\n",
687 command
, strerror(save_errno
));
691 if (WIFEXITED(status
)) {
692 int pstatus
= WEXITSTATUS(status
);
693 if (WIFSIGNALED(status
)) {
694 fprintf(stderr
, "%s terminated with signal %d\n",
695 command
, WTERMSIG(status
));
697 } else if (pstatus
>= 64 && pstatus
< 255) {
698 fprintf(stderr
, "%s failed with error %d\n",
699 command
, pstatus
-64);
705 } else if (WIFSIGNALED(status
)) {
706 fprintf(stderr
, "%s terminated with signal %d\n",
707 command
, WTERMSIG(status
));
718 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
719 int argc
, const char **argv
)
721 printf("%s\n", ctdb_version_string
);
725 static bool partially_online(TALLOC_CTX
*mem_ctx
,
726 struct ctdb_context
*ctdb
,
727 struct ctdb_node_and_flags
*node
)
729 struct ctdb_iface_list
*iface_list
;
733 if (node
->flags
!= 0) {
737 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
738 node
->pnn
, TIMEOUT(), &iface_list
);
744 for (i
=0; i
< iface_list
->num
; i
++) {
745 if (iface_list
->iface
[i
].link_state
== 0) {
754 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
755 struct ctdb_context
*ctdb
,
756 struct ctdb_node_map
*nodemap
,
759 struct ctdb_node_and_flags
*node
;
762 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
766 "Disconnected", options
.sep
,
767 "Banned", options
.sep
,
768 "Disabled", options
.sep
,
769 "Unhealthy", options
.sep
,
770 "Stopped", options
.sep
,
771 "Inactive", options
.sep
,
772 "PartiallyOnline", options
.sep
,
773 "ThisNode", options
.sep
);
775 for (i
=0; i
<nodemap
->num
; i
++) {
776 node
= &nodemap
->node
[i
];
777 if (node
->flags
& NODE_FLAGS_DELETED
) {
781 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
783 node
->pnn
, options
.sep
,
784 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
786 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
787 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
788 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
790 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
791 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
792 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
793 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
794 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
799 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
800 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
803 struct ctdb_node_and_flags
*node
;
804 int num_deleted_nodes
= 0;
807 for (i
=0; i
<nodemap
->num
; i
++) {
808 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
814 if (num_deleted_nodes
== 0) {
815 printf("Number of nodes:%d\n", nodemap
->num
);
817 printf("Number of nodes:%d "
818 "(including %d deleted nodes)\n",
819 nodemap
->num
, num_deleted_nodes
);
823 for (i
=0; i
<nodemap
->num
; i
++) {
824 node
= &nodemap
->node
[i
];
825 if (node
->flags
& NODE_FLAGS_DELETED
) {
829 printf("pnn:%u %-16s %s%s\n",
831 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
832 partially_online(mem_ctx
, ctdb
, node
) ?
834 pretty_print_flags(mem_ctx
, node
->flags
),
835 node
->pnn
== mypnn
? " (THIS NODE)" : "");
839 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
840 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
841 struct ctdb_vnn_map
*vnnmap
, int recmode
,
846 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
848 if (vnnmap
->generation
== INVALID_GENERATION
) {
849 printf("Generation:INVALID\n");
851 printf("Generation:%u\n", vnnmap
->generation
);
853 printf("Size:%d\n", vnnmap
->size
);
854 for (i
=0; i
<vnnmap
->size
; i
++) {
855 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
858 printf("Recovery mode:%s (%d)\n",
859 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
861 printf("Recovery master:%d\n", recmaster
);
864 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
865 int argc
, const char **argv
)
867 struct ctdb_node_map
*nodemap
;
868 struct ctdb_vnn_map
*vnnmap
;
877 nodemap
= get_nodemap(ctdb
, false);
878 if (nodemap
== NULL
) {
882 if (options
.machinereadable
== 1) {
883 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
887 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
888 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
893 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
894 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
899 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
900 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
905 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
910 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
911 int argc
, const char **argv
)
913 struct ctdb_uptime
*uptime
;
914 int ret
, tmp
, days
, hours
, minutes
, seconds
;
916 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
917 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
922 printf("Current time of node %-4u : %s",
923 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
925 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
926 seconds
= tmp
% 60; tmp
/= 60;
927 minutes
= tmp
% 60; tmp
/= 60;
928 hours
= tmp
% 24; tmp
/= 24;
931 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
932 days
, hours
, minutes
, seconds
,
933 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
935 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
936 seconds
= tmp
% 60; tmp
/= 60;
937 minutes
= tmp
% 60; tmp
/= 60;
938 hours
= tmp
% 24; tmp
/= 24;
941 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
942 days
, hours
, minutes
, seconds
,
943 ctime(&uptime
->last_recovery_finished
.tv_sec
));
945 printf("Duration of last recovery/failover: %lf seconds\n",
946 timeval_delta(&uptime
->last_recovery_finished
,
947 &uptime
->last_recovery_started
));
952 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
953 int argc
, const char **argv
)
956 int ret
, num_clients
;
958 tv
= timeval_current();
959 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
960 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
965 printf("response from %u time=%.6f sec (%d clients)\n",
966 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
970 const char *runstate_to_string(enum ctdb_runstate runstate
);
971 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
973 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
974 int argc
, const char **argv
)
976 enum ctdb_runstate runstate
;
980 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
981 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
987 for (i
=0; i
<argc
; i
++) {
988 enum ctdb_runstate t
;
991 t
= ctdb_runstate_from_string(argv
[i
]);
992 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
993 printf("Invalid run state (%s)\n", argv
[i
]);
1004 printf("CTDB not in required run state (got %s)\n",
1005 ctdb_runstate_to_string(runstate
));
1009 printf("%s\n", ctdb_runstate_to_string(runstate
));
1013 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1014 int argc
, const char **argv
)
1016 struct ctdb_var_list
*tun_var_list
;
1025 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1026 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1029 "Failed to get list of variables from node %u\n",
1035 for (i
=0; i
<tun_var_list
->count
; i
++) {
1036 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1043 printf("No such tunable %s\n", argv
[0]);
1047 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1048 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1053 printf("%-26s = %u\n", argv
[0], value
);
1057 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1058 int argc
, const char **argv
)
1060 struct ctdb_var_list
*tun_var_list
;
1061 struct ctdb_tunable tunable
;
1069 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1070 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1073 "Failed to get list of variables from node %u\n",
1079 for (i
=0; i
<tun_var_list
->count
; i
++) {
1080 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1087 printf("No such tunable %s\n", argv
[0]);
1091 tunable
.name
= argv
[0];
1092 tunable
.value
= strtoul(argv
[1], NULL
, 0);
1094 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1095 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1099 "Setting obsolete tunable variable '%s'\n",
1108 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1109 int argc
, const char **argv
)
1111 struct ctdb_var_list
*tun_var_list
;
1118 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1119 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1124 for (i
=0; i
<tun_var_list
->count
; i
++) {
1125 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1134 } stats_fields
[] = {
1135 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1136 STATISTICS_FIELD(num_clients
),
1137 STATISTICS_FIELD(frozen
),
1138 STATISTICS_FIELD(recovering
),
1139 STATISTICS_FIELD(num_recoveries
),
1140 STATISTICS_FIELD(client_packets_sent
),
1141 STATISTICS_FIELD(client_packets_recv
),
1142 STATISTICS_FIELD(node_packets_sent
),
1143 STATISTICS_FIELD(node_packets_recv
),
1144 STATISTICS_FIELD(keepalive_packets_sent
),
1145 STATISTICS_FIELD(keepalive_packets_recv
),
1146 STATISTICS_FIELD(node
.req_call
),
1147 STATISTICS_FIELD(node
.reply_call
),
1148 STATISTICS_FIELD(node
.req_dmaster
),
1149 STATISTICS_FIELD(node
.reply_dmaster
),
1150 STATISTICS_FIELD(node
.reply_error
),
1151 STATISTICS_FIELD(node
.req_message
),
1152 STATISTICS_FIELD(node
.req_control
),
1153 STATISTICS_FIELD(node
.reply_control
),
1154 STATISTICS_FIELD(node
.req_tunnel
),
1155 STATISTICS_FIELD(client
.req_call
),
1156 STATISTICS_FIELD(client
.req_message
),
1157 STATISTICS_FIELD(client
.req_control
),
1158 STATISTICS_FIELD(client
.req_tunnel
),
1159 STATISTICS_FIELD(timeouts
.call
),
1160 STATISTICS_FIELD(timeouts
.control
),
1161 STATISTICS_FIELD(timeouts
.traverse
),
1162 STATISTICS_FIELD(locks
.num_calls
),
1163 STATISTICS_FIELD(locks
.num_current
),
1164 STATISTICS_FIELD(locks
.num_pending
),
1165 STATISTICS_FIELD(locks
.num_failed
),
1166 STATISTICS_FIELD(total_calls
),
1167 STATISTICS_FIELD(pending_calls
),
1168 STATISTICS_FIELD(childwrite_calls
),
1169 STATISTICS_FIELD(pending_childwrite_calls
),
1170 STATISTICS_FIELD(memory_used
),
1171 STATISTICS_FIELD(max_hop_count
),
1172 STATISTICS_FIELD(total_ro_delegations
),
1173 STATISTICS_FIELD(total_ro_revokes
),
1176 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1178 static void print_statistics_machine(struct ctdb_statistics
*s
,
1184 printf("CTDB version%s", options
.sep
);
1185 printf("Current time of statistics%s", options
.sep
);
1186 printf("Statistics collected since%s", options
.sep
);
1187 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1188 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1190 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1191 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1192 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1193 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1195 printf("num_reclock_recd_latency%s", options
.sep
);
1196 printf("min_reclock_recd_latency%s", options
.sep
);
1197 printf("avg_reclock_recd_latency%s", options
.sep
);
1198 printf("max_reclock_recd_latency%s", options
.sep
);
1200 printf("num_call_latency%s", options
.sep
);
1201 printf("min_call_latency%s", options
.sep
);
1202 printf("avg_call_latency%s", options
.sep
);
1203 printf("max_call_latency%s", options
.sep
);
1205 printf("num_lockwait_latency%s", options
.sep
);
1206 printf("min_lockwait_latency%s", options
.sep
);
1207 printf("avg_lockwait_latency%s", options
.sep
);
1208 printf("max_lockwait_latency%s", options
.sep
);
1210 printf("num_childwrite_latency%s", options
.sep
);
1211 printf("min_childwrite_latency%s", options
.sep
);
1212 printf("avg_childwrite_latency%s", options
.sep
);
1213 printf("max_childwrite_latency%s", options
.sep
);
1217 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1218 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1219 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1220 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1222 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1225 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1226 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1227 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1228 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1230 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1231 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1232 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1233 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1235 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1236 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1237 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1238 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1240 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1241 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1242 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1243 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1247 static void print_statistics(struct ctdb_statistics
*s
)
1249 int tmp
, days
, hours
, minutes
, seconds
;
1251 const char *prefix
= NULL
;
1254 tmp
= s
->statistics_current_time
.tv_sec
-
1255 s
->statistics_start_time
.tv_sec
;
1256 seconds
= tmp
% 60; tmp
/= 60;
1257 minutes
= tmp
% 60; tmp
/= 60;
1258 hours
= tmp
% 24; tmp
/= 24;
1261 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1262 printf("Current time of statistics : %s",
1263 ctime(&s
->statistics_current_time
.tv_sec
));
1264 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1265 days
, hours
, minutes
, seconds
,
1266 ctime(&s
->statistics_start_time
.tv_sec
));
1268 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1269 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1270 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1272 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1273 prefix
= stats_fields
[i
].name
;
1274 printf(" %*.*s\n", preflen
-1, preflen
-1,
1275 stats_fields
[i
].name
);
1280 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1281 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1282 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1285 printf(" hop_count_buckets:");
1286 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1287 printf(" %d", s
->hop_count_bucket
[i
]);
1290 printf(" lock_buckets:");
1291 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1292 printf(" %d", s
->locks
.buckets
[i
]);
1295 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1296 "locks_latency MIN/AVG/MAX",
1297 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1298 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1300 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1301 "reclock_ctdbd MIN/AVG/MAX",
1302 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1303 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1305 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1306 "reclock_recd MIN/AVG/MAX",
1307 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1308 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1310 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1311 "call_latency MIN/AVG/MAX",
1312 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1313 s
->call_latency
.max
, s
->call_latency
.num
);
1315 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1316 "childwrite_latency MIN/AVG/MAX",
1317 s
->childwrite_latency
.min
,
1318 LATENCY_AVG(s
->childwrite_latency
),
1319 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1322 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1323 int argc
, const char **argv
)
1325 struct ctdb_statistics
*stats
;
1329 usage("statistics");
1332 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1333 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1338 if (options
.machinereadable
) {
1339 print_statistics_machine(stats
, true);
1341 print_statistics(stats
);
1347 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1348 struct ctdb_context
*ctdb
,
1349 int argc
, const char **argv
)
1354 usage("statisticsreset");
1357 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1358 ctdb
->cmd_pnn
, TIMEOUT());
1366 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1367 int argc
, const char **argv
)
1369 struct ctdb_statistics_list
*slist
;
1370 int ret
, count
= 0, i
;
1371 bool show_header
= true;
1378 count
= atoi(argv
[0]);
1381 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1382 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1387 for (i
=0; i
<slist
->num
; i
++) {
1388 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1391 if (options
.machinereadable
== 1) {
1392 print_statistics_machine(&slist
->stats
[i
],
1394 show_header
= false;
1396 print_statistics(&slist
->stats
[i
]);
1398 if (count
> 0 && i
== count
) {
1406 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1408 const struct ctdb_public_ip
*ip_a
= a
;
1409 const struct ctdb_public_ip
*ip_b
= b
;
1411 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1414 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1415 struct ctdb_public_ip_list
*ips
,
1416 struct ctdb_public_ip_info
**ipinfo
,
1420 char *conf
, *avail
, *active
;
1422 if (options
.machinereadable
== 1) {
1423 printf("%s%s%s%s%s", options
.sep
,
1424 "Public IP", options
.sep
,
1425 "Node", options
.sep
);
1426 if (options
.verbose
== 1) {
1427 printf("%s%s%s%s%s%s\n",
1428 "ActiveInterfaces", options
.sep
,
1429 "AvailableInterfaces", options
.sep
,
1430 "ConfiguredInterfaces", options
.sep
);
1436 printf("Public IPs on ALL nodes\n");
1438 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1442 for (i
= 0; i
< ips
->num
; i
++) {
1444 if (options
.machinereadable
== 1) {
1445 printf("%s%s%s%d%s", options
.sep
,
1446 ctdb_sock_addr_to_string(
1447 mem_ctx
, &ips
->ip
[i
].addr
, false),
1449 (int)ips
->ip
[i
].pnn
, options
.sep
);
1451 printf("%s", ctdb_sock_addr_to_string(
1452 mem_ctx
, &ips
->ip
[i
].addr
, false));
1455 if (options
.verbose
== 0) {
1456 if (options
.machinereadable
== 1) {
1459 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1468 if (ipinfo
[i
] == NULL
) {
1472 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1473 struct ctdb_iface
*iface
;
1475 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1477 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1479 conf
= talloc_asprintf_append(
1480 conf
, ",%s", iface
->name
);
1483 if (ipinfo
[i
]->active_idx
== j
) {
1484 active
= iface
->name
;
1487 if (iface
->link_state
== 0) {
1491 if (avail
== NULL
) {
1492 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1494 avail
= talloc_asprintf_append(
1495 avail
, ",%s", iface
->name
);
1501 if (options
.machinereadable
== 1) {
1502 printf("%s%s%s%s%s%s\n",
1503 active
? active
: "", options
.sep
,
1504 avail
? avail
: "", options
.sep
,
1505 conf
? conf
: "", options
.sep
);
1507 printf(" node[%d] active[%s] available[%s]"
1508 " configured[%s]\n",
1509 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1510 avail
? avail
: "", conf
? conf
: "");
1515 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1516 size_t datalen
, void *private_data
)
1518 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1519 private_data
, struct ctdb_public_ip_list
);
1520 struct ctdb_public_ip
*ip
;
1522 ip
= (struct ctdb_public_ip
*)databuf
;
1523 ips
->ip
[ips
->num
] = *ip
;
1529 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1530 struct ctdb_public_ip_list
**out
)
1532 struct ctdb_node_map
*nodemap
;
1533 struct ctdb_public_ip_list
*ips
;
1534 struct db_hash_context
*ipdb
;
1536 int ret
, count
, i
, j
;
1538 nodemap
= get_nodemap(ctdb
, false);
1539 if (nodemap
== NULL
) {
1543 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1548 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1554 for (i
=0; i
<count
; i
++) {
1555 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1556 pnn_list
[i
], TIMEOUT(),
1562 for (j
=0; j
<ips
->num
; j
++) {
1563 struct ctdb_public_ip ip
;
1565 ip
.pnn
= ips
->ip
[j
].pnn
;
1566 ip
.addr
= ips
->ip
[j
].addr
;
1568 if (pnn_list
[i
] == ip
.pnn
) {
1569 /* Node claims IP is hosted on it, so
1570 * save that information
1572 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1574 (uint8_t *)&ip
, sizeof(ip
));
1579 /* Node thinks IP is hosted elsewhere,
1580 * so overwrite with CTDB_UNKNOWN_PNN
1581 * if there's no existing entry
1583 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1585 if (ret
== ENOENT
) {
1586 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1587 ret
= db_hash_add(ipdb
,
1588 (uint8_t *)&ip
.addr
,
1602 talloc_free(pnn_list
);
1604 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1609 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1614 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1615 if (ips
->ip
== NULL
) {
1619 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1624 if (count
!= ips
->num
) {
1638 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1639 int argc
, const char **argv
)
1641 struct ctdb_public_ip_list
*ips
;
1642 struct ctdb_public_ip_info
**ipinfo
;
1644 bool do_all
= false;
1651 if (strcmp(argv
[0], "all") == 0) {
1659 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1661 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1662 ctdb
->cmd_pnn
, TIMEOUT(),
1669 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1670 ctdb_public_ip_cmp
);
1672 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1673 if (ipinfo
== NULL
) {
1677 for (i
=0; i
<ips
->num
; i
++) {
1680 pnn
= ips
->ip
[i
].pnn
;
1682 pnn
= ctdb
->cmd_pnn
;
1684 if (pnn
== CTDB_UNKNOWN_PNN
) {
1688 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1690 TIMEOUT(), &ips
->ip
[i
].addr
,
1697 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1701 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1702 int argc
, const char **argv
)
1704 struct ctdb_public_ip_info
*ipinfo
;
1705 ctdb_sock_addr addr
;
1712 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1714 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1718 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1719 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1723 printf("Node %u does not know about IP %s\n",
1724 ctdb
->cmd_pnn
, argv
[0]);
1729 printf("Public IP[%s] info on node %u\n",
1730 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1733 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1734 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1735 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1737 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1738 struct ctdb_iface
*iface
;
1740 iface
= &ipinfo
->ifaces
->iface
[i
];
1741 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1742 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1744 iface
->link_state
== 0 ? "down" : "up",
1746 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1752 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1753 int argc
, const char **argv
)
1755 struct ctdb_iface_list
*ifaces
;
1762 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1763 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1768 if (ifaces
->num
== 0) {
1769 printf("No interfaces configured on node %u\n",
1774 if (options
.machinereadable
) {
1775 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1776 "Name", options
.sep
,
1777 "LinkStatus", options
.sep
,
1778 "References", options
.sep
);
1780 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1783 for (i
=0; i
<ifaces
->num
; i
++) {
1784 if (options
.machinereadable
) {
1785 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1786 ifaces
->iface
[i
].name
, options
.sep
,
1787 ifaces
->iface
[i
].link_state
, options
.sep
,
1788 ifaces
->iface
[i
].references
, options
.sep
);
1790 printf("name:%s link:%s references:%u\n",
1791 ifaces
->iface
[i
].name
,
1792 ifaces
->iface
[i
].link_state
? "up" : "down",
1793 ifaces
->iface
[i
].references
);
1800 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1801 int argc
, const char **argv
)
1803 struct ctdb_iface_list
*ifaces
;
1804 struct ctdb_iface
*iface
;
1808 usage("setifacelink");
1811 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1812 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1816 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1817 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1820 "Failed to get interface information from node %u\n",
1826 for (i
=0; i
<ifaces
->num
; i
++) {
1827 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1828 iface
= &ifaces
->iface
[i
];
1833 if (iface
== NULL
) {
1834 printf("Interface %s not configured on node %u\n",
1835 argv
[0], ctdb
->cmd_pnn
);
1839 if (strcmp(argv
[1], "up") == 0) {
1840 iface
->link_state
= 1;
1841 } else if (strcmp(argv
[1], "down") == 0) {
1842 iface
->link_state
= 0;
1844 usage("setifacelink");
1848 iface
->references
= 0;
1850 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1851 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1859 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1860 struct ctdb_context
*ctdb
,
1861 int argc
, const char **argv
)
1867 if (argc
!= 1 && argc
!= 2) {
1868 usage("process-exists");
1871 pid
= atoi(argv
[0]);
1873 srvid
= strtoull(argv
[1], NULL
, 0);
1877 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1878 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1880 struct ctdb_pid_srvid pid_srvid
;
1882 pid_srvid
.pid
= pid
;
1883 pid_srvid
.srvid
= srvid
;
1885 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
1886 ctdb
->client
, ctdb
->cmd_pnn
,
1887 TIMEOUT(), &pid_srvid
,
1896 printf("PID %d %s\n", pid
,
1897 (status
== 0 ? "exists" : "does not exist"));
1899 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
1900 (status
== 0 ? "exists" : "does not exist"));
1905 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1906 int argc
, const char **argv
)
1908 struct ctdb_dbid_map
*dbmap
;
1915 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1916 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1921 if (options
.machinereadable
== 1) {
1922 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1925 "Name", options
.sep
,
1926 "Path", options
.sep
,
1927 "Persistent", options
.sep
,
1928 "Sticky", options
.sep
,
1929 "Unhealthy", options
.sep
,
1930 "Readonly", options
.sep
,
1931 "Replicated", options
.sep
);
1933 printf("Number of databases:%d\n", dbmap
->num
);
1936 for (i
=0; i
<dbmap
->num
; i
++) {
1946 db_id
= dbmap
->dbs
[i
].db_id
;
1948 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1949 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1955 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1956 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1962 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1963 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1969 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
1970 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
1971 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
1972 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
1974 if (options
.machinereadable
== 1) {
1975 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1980 !! (persistent
), options
.sep
,
1981 !! (sticky
), options
.sep
,
1982 !! (health
), options
.sep
,
1983 !! (readonly
), options
.sep
,
1984 !! (replicated
), options
.sep
);
1986 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1988 persistent
? " PERSISTENT" : "",
1989 sticky
? " STICKY" : "",
1990 readonly
? " READONLY" : "",
1991 replicated
? " REPLICATED" : "",
1992 health
? " UNHEALTHY" : "");
1995 talloc_free(discard_const(name
));
1996 talloc_free(discard_const(path
));
1997 talloc_free(discard_const(health
));
2003 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2004 int argc
, const char **argv
)
2007 const char *db_name
, *db_path
, *db_health
;
2012 usage("getdbstatus");
2015 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2019 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2020 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2026 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2027 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2033 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2034 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2035 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2036 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2037 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2038 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2039 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2043 struct dump_record_state
{
2047 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2049 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2053 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2054 for (i
=0; i
<val
.dsize
; i
++) {
2055 if (ISASCII(val
.dptr
[i
])) {
2056 fprintf(stdout
, "%c", val
.dptr
[i
]);
2058 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2061 fprintf(stdout
, "\"\n");
2064 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2066 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2067 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2068 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2069 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2070 fprintf(stdout
, " MIGRATED_WITH_DATA");
2072 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2073 fprintf(stdout
, " VACUUM_MIGRATED");
2075 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2076 fprintf(stdout
, " AUTOMATIC");
2078 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2079 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2081 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2082 fprintf(stdout
, " RO_HAVE_READONLY");
2084 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2085 fprintf(stdout
, " RO_REVOKING_READONLY");
2087 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2088 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2090 fprintf(stdout
, "\n");
2094 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2095 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2097 struct dump_record_state
*state
=
2098 (struct dump_record_state
*)private_data
;
2102 dump_tdb_data("key", key
);
2103 dump_ltdb_header(header
);
2104 dump_tdb_data("data", data
);
2105 fprintf(stdout
, "\n");
2110 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2111 int argc
, const char **argv
)
2113 struct ctdb_db_context
*db
;
2114 const char *db_name
;
2117 struct dump_record_state state
;
2124 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2128 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2131 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2137 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2138 ctdb
->cmd_pnn
, TIMEOUT(),
2139 dump_record
, &state
);
2141 printf("Dumped %u records\n", state
.count
);
2146 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2147 int argc
, const char **argv
)
2149 struct ctdb_db_context
*db
;
2150 const char *db_name
;
2153 struct dump_record_state state
;
2160 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2164 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2167 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2172 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2174 printf("Dumped %u record(s)\n", state
.count
);
2179 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2180 struct ctdb_context
*ctdb
,
2181 int argc
, const char **argv
)
2187 usage("getcapabilities");
2190 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2191 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2196 if (options
.machinereadable
== 1) {
2197 printf("%s%s%s%s%s\n",
2199 "RECMASTER", options
.sep
,
2200 "LMASTER", options
.sep
);
2201 printf("%s%d%s%d%s\n", options
.sep
,
2202 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2203 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2205 printf("RECMASTER: %s\n",
2206 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2207 printf("LMASTER: %s\n",
2208 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2214 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2215 int argc
, const char **argv
)
2217 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2221 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2222 int argc
, const char **argv
)
2224 char *t
, *lvs_helper
= NULL
;
2230 t
= getenv("CTDB_LVS_HELPER");
2232 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2234 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2235 CTDB_HELPER_BINDIR
);
2238 if (lvs_helper
== NULL
) {
2239 fprintf(stderr
, "Unable to set LVS helper\n");
2243 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2246 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2247 int argc
, const char **argv
)
2257 found
= debug_level_parse(argv
[0], &log_level
);
2260 "Invalid debug level '%s'. Valid levels are:\n",
2262 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2266 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2267 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2275 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2276 int argc
, const char **argv
)
2279 const char *log_str
;
2286 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2287 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2292 log_str
= debug_level_to_string(loglevel
);
2293 printf("%s\n", log_str
);
2298 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2299 int argc
, const char **argv
)
2301 const char *db_name
;
2302 uint8_t db_flags
= 0;
2305 if (argc
< 1 || argc
> 2) {
2311 if (strcmp(argv
[1], "persistent") == 0) {
2312 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2313 } else if (strcmp(argv
[1], "readonly") == 0) {
2314 db_flags
= CTDB_DB_FLAGS_READONLY
;
2315 } else if (strcmp(argv
[1], "sticky") == 0) {
2316 db_flags
= CTDB_DB_FLAGS_STICKY
;
2317 } else if (strcmp(argv
[1], "replicated") == 0) {
2318 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2324 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2333 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2334 int argc
, const char **argv
)
2336 const char *db_name
;
2339 struct ctdb_node_map
*nodemap
;
2347 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2348 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2353 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2354 fprintf(stderr
, "Database cannot be detached"
2355 " when recovery is active\n");
2359 nodemap
= get_nodemap(ctdb
, false);
2360 if (nodemap
== NULL
) {
2364 for (i
=0; i
<nodemap
->num
; i
++) {
2367 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
2370 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
2373 if (nodemap
->node
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2374 fprintf(stderr
, "Database cannot be detached on"
2375 " inactive (stopped or banned) node %u\n",
2376 nodemap
->node
[i
].pnn
);
2380 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2381 nodemap
->node
[i
].pnn
, TIMEOUT(),
2382 "AllowClientDBAttach", &value
);
2385 "Unable to get tunable AllowClientDBAttach"
2386 " from node %u\n", nodemap
->node
[i
].pnn
);
2392 "Database access is still active on node %u."
2393 " Set AllowclientDBAttach=0 on all nodes.\n",
2394 nodemap
->node
[i
].pnn
);
2400 for (i
=0; i
<argc
; i
++) {
2401 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2407 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2409 "Only volatile databases can be detached\n");
2413 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2415 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2423 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2424 int argc
, const char **argv
)
2426 const char *mem_str
;
2430 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2431 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2436 n
= write(1, mem_str
, strlen(mem_str
)+1);
2437 if (n
< 0 || n
!= strlen(mem_str
)+1) {
2438 fprintf(stderr
, "Failed to write talloc summary\n");
2445 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2447 bool *done
= (bool *)private_data
;
2450 n
= write(1, data
.dptr
, data
.dsize
);
2451 if (n
< 0 || n
!= data
.dsize
) {
2452 fprintf(stderr
, "Failed to write talloc summary\n");
2458 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2459 int argc
, const char **argv
)
2461 struct ctdb_srvid_message msg
= { 0 };
2465 msg
.pnn
= ctdb
->pnn
;
2466 msg
.srvid
= next_srvid(ctdb
);
2468 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2469 msg
.srvid
, dump_memory
, &done
);
2474 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2475 ctdb
->cmd_pnn
, &msg
);
2480 ctdb_client_wait(ctdb
->ev
, &done
);
2484 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2485 int argc
, const char **argv
)
2490 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2491 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2496 printf("%u\n", pid
);
2500 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2501 const char *desc
, uint32_t flag
, bool set_flag
)
2503 struct ctdb_node_map
*nodemap
;
2506 nodemap
= get_nodemap(ctdb
, false);
2507 if (nodemap
== NULL
) {
2511 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2512 if (set_flag
== flag_is_set
) {
2514 fprintf(stderr
, "Node %u is already %s\n",
2515 ctdb
->cmd_pnn
, desc
);
2517 fprintf(stderr
, "Node %u is not %s\n",
2518 ctdb
->cmd_pnn
, desc
);
2526 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2527 uint32_t flag
, bool set_flag
)
2529 struct ctdb_node_map
*nodemap
;
2533 nodemap
= get_nodemap(ctdb
, true);
2534 if (nodemap
== NULL
) {
2536 "Failed to get nodemap, trying again\n");
2541 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2542 if (flag_is_set
== set_flag
) {
2550 static int ctdb_ctrl_modflags(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
2551 struct ctdb_client_context
*client
,
2552 uint32_t destnode
, struct timeval timeout
,
2553 uint32_t set
, uint32_t clear
)
2555 struct ctdb_node_map
*nodemap
;
2556 struct ctdb_node_flag_change flag_change
;
2557 struct ctdb_req_control request
;
2561 ret
= ctdb_ctrl_get_nodemap(mem_ctx
, ev
, client
, destnode
,
2562 tevent_timeval_zero(), &nodemap
);
2567 flag_change
.pnn
= destnode
;
2568 flag_change
.old_flags
= nodemap
->node
[destnode
].flags
;
2569 flag_change
.new_flags
= flag_change
.old_flags
| set
;
2570 flag_change
.new_flags
&= ~clear
;
2572 count
= list_of_connected_nodes(nodemap
, -1, mem_ctx
, &pnn_list
);
2577 ctdb_req_control_modify_flags(&request
, &flag_change
);
2578 ret
= ctdb_client_control_multi(mem_ctx
, ev
, client
, pnn_list
, count
,
2579 tevent_timeval_zero(), &request
,
2584 struct ipreallocate_state
{
2589 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2592 struct ipreallocate_state
*state
=
2593 (struct ipreallocate_state
*)private_data
;
2595 if (data
.dsize
!= sizeof(int)) {
2600 state
->status
= *(int *)data
.dptr
;
2604 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2606 struct ctdb_srvid_message msg
= { 0 };
2607 struct ipreallocate_state state
;
2610 msg
.pnn
= ctdb
->pnn
;
2611 msg
.srvid
= next_srvid(ctdb
);
2614 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2616 ipreallocate_handler
, &state
);
2622 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2624 CTDB_BROADCAST_CONNECTED
,
2630 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2636 if (state
.status
>= 0) {
2645 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2650 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2651 int argc
, const char **argv
)
2659 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2660 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2665 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2666 ctdb
->cmd_pnn
, TIMEOUT(),
2667 NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2670 "Failed to set DISABLED flag on node %u\n",
2675 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2676 return ipreallocate(mem_ctx
, ctdb
);
2679 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2680 int argc
, const char **argv
)
2688 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2689 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2694 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2695 ctdb
->cmd_pnn
, TIMEOUT(),
2696 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2698 fprintf(stderr
, "Failed to reset DISABLED flag on node %u\n",
2703 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2704 return ipreallocate(mem_ctx
, ctdb
);
2707 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2708 int argc
, const char **argv
)
2716 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2717 NODE_FLAGS_STOPPED
, true);
2722 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2723 ctdb
->cmd_pnn
, TIMEOUT());
2725 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2729 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2730 return ipreallocate(mem_ctx
, ctdb
);
2733 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2734 int argc
, const char **argv
)
2742 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2743 NODE_FLAGS_STOPPED
, false);
2748 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2749 ctdb
->cmd_pnn
, TIMEOUT());
2751 fprintf(stderr
, "Failed to continue stopped node %u\n",
2756 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2757 return ipreallocate(mem_ctx
, ctdb
);
2760 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2761 int argc
, const char **argv
)
2763 struct ctdb_ban_state ban_state
;
2770 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2771 NODE_FLAGS_BANNED
, true);
2776 ban_state
.pnn
= ctdb
->cmd_pnn
;
2777 ban_state
.time
= strtoul(argv
[0], NULL
, 0);
2779 if (ban_state
.time
== 0) {
2780 fprintf(stderr
, "Ban time cannot be zero\n");
2784 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2785 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2787 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2791 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2792 return ipreallocate(mem_ctx
, ctdb
);
2796 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2797 int argc
, const char **argv
)
2799 struct ctdb_ban_state ban_state
;
2806 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2807 NODE_FLAGS_BANNED
, false);
2812 ban_state
.pnn
= ctdb
->cmd_pnn
;
2815 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2816 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2818 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2822 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2823 return ipreallocate(mem_ctx
, ctdb
);
2827 static void wait_for_shutdown(void *private_data
)
2829 bool *done
= (bool *)private_data
;
2834 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2835 int argc
, const char **argv
)
2844 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2845 ctdb_client_set_disconnect_callback(ctdb
->client
,
2850 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2851 ctdb
->cmd_pnn
, TIMEOUT());
2853 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2857 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2858 ctdb_client_wait(ctdb
->ev
, &done
);
2864 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2865 uint32_t *generation
)
2869 struct ctdb_vnn_map
*vnnmap
;
2873 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2874 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2876 fprintf(stderr
, "Failed to find recovery master\n");
2880 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2881 recmaster
, TIMEOUT(), &recmode
);
2883 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2888 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2893 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2894 recmaster
, TIMEOUT(), &vnnmap
);
2896 fprintf(stderr
, "Failed to get generation from node %u\n",
2901 if (vnnmap
->generation
== INVALID_GENERATION
) {
2902 talloc_free(vnnmap
);
2907 *generation
= vnnmap
->generation
;
2908 talloc_free(vnnmap
);
2913 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2914 int argc
, const char **argv
)
2916 uint32_t generation
, next_generation
;
2923 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2928 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2929 ctdb
->cmd_pnn
, TIMEOUT(),
2930 CTDB_RECOVERY_ACTIVE
);
2932 fprintf(stderr
, "Failed to set recovery mode active\n");
2937 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2940 "Failed to confirm end of recovery\n");
2944 if (next_generation
!= generation
) {
2954 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2955 int argc
, const char **argv
)
2958 usage("ipreallocate");
2961 return ipreallocate(mem_ctx
, ctdb
);
2964 static int control_isnotrecmaster(TALLOC_CTX
*mem_ctx
,
2965 struct ctdb_context
*ctdb
,
2966 int argc
, const char **argv
)
2972 usage("isnotrecmaster");
2975 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2976 ctdb
->pnn
, TIMEOUT(), &recmaster
);
2978 fprintf(stderr
, "Failed to get recmaster\n");
2982 if (recmaster
!= ctdb
->pnn
) {
2983 printf("this node is not the recmaster\n");
2987 printf("this node is the recmaster\n");
2991 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2992 int argc
, const char **argv
)
2994 struct ctdb_addr_info addr_info
;
3001 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
3003 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3006 addr_info
.iface
= argv
[1];
3008 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3009 ctdb
->cmd_pnn
, TIMEOUT(),
3012 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3020 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3021 int argc
, const char **argv
)
3023 ctdb_sock_addr src
, dst
;
3026 if (argc
!= 0 && argc
!= 2) {
3031 struct ctdb_connection_list
*clist
;
3033 unsigned int num_failed
;
3035 /* Client first but the src/dst logic is confused */
3036 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3042 for (i
= 0; i
< clist
->num
; i
++) {
3043 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3044 &clist
->conn
[i
].dst
,
3053 if (num_failed
> 0) {
3054 fprintf(stderr
, "Failed to send %d tickles\n",
3063 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3065 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3069 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3071 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3075 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3077 fprintf(stderr
, "Failed to send tickle ack\n");
3084 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3085 int argc
, const char **argv
)
3087 ctdb_sock_addr addr
;
3088 struct ctdb_tickle_list
*tickles
;
3092 if (argc
< 1 || argc
> 2) {
3093 usage("gettickles");
3097 port
= strtoul(argv
[1], NULL
, 10);
3100 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3102 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3105 ctdb_sock_addr_set_port(&addr
, port
);
3107 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3108 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3111 fprintf(stderr
, "Failed to get list of connections\n");
3115 if (options
.machinereadable
) {
3116 printf("%s%s%s%s%s%s%s%s%s\n",
3118 "Source IP", options
.sep
,
3119 "Port", options
.sep
,
3120 "Destiation IP", options
.sep
,
3121 "Port", options
.sep
);
3122 for (i
=0; i
<tickles
->num
; i
++) {
3123 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3124 ctdb_sock_addr_to_string(
3125 mem_ctx
, &tickles
->conn
[i
].src
, false),
3127 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3129 ctdb_sock_addr_to_string(
3130 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3132 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3136 printf("Connections for IP: %s\n",
3137 ctdb_sock_addr_to_string(mem_ctx
,
3138 &tickles
->addr
, false));
3139 printf("Num connections: %u\n", tickles
->num
);
3140 for (i
=0; i
<tickles
->num
; i
++) {
3141 printf("SRC: %s DST: %s\n",
3142 ctdb_sock_addr_to_string(
3143 mem_ctx
, &tickles
->conn
[i
].src
, true),
3144 ctdb_sock_addr_to_string(
3145 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3149 talloc_free(tickles
);
3153 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3154 struct ctdb_connection
*conn
);
3156 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3158 struct process_clist_state
{
3159 struct ctdb_connection_list
*clist
;
3161 int num_failed
, num_total
;
3162 clist_reply_func reply_func
;
3165 static void process_clist_done(struct tevent_req
*subreq
);
3167 static struct tevent_req
*process_clist_send(
3168 TALLOC_CTX
*mem_ctx
,
3169 struct ctdb_context
*ctdb
,
3170 struct ctdb_connection_list
*clist
,
3171 clist_request_func request_func
,
3172 clist_reply_func reply_func
)
3174 struct tevent_req
*req
, *subreq
;
3175 struct process_clist_state
*state
;
3176 struct ctdb_req_control request
;
3179 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3184 state
->clist
= clist
;
3185 state
->reply_func
= reply_func
;
3187 for (i
= 0; i
< clist
->num
; i
++) {
3188 request_func(&request
, &clist
->conn
[i
]);
3189 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3190 ctdb
->client
, ctdb
->cmd_pnn
,
3191 TIMEOUT(), &request
);
3192 if (tevent_req_nomem(subreq
, req
)) {
3193 return tevent_req_post(req
, ctdb
->ev
);
3195 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3201 static void process_clist_done(struct tevent_req
*subreq
)
3203 struct tevent_req
*req
= tevent_req_callback_data(
3204 subreq
, struct tevent_req
);
3205 struct process_clist_state
*state
= tevent_req_data(
3206 req
, struct process_clist_state
);
3207 struct ctdb_reply_control
*reply
;
3211 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3212 TALLOC_FREE(subreq
);
3214 state
->num_failed
+= 1;
3218 ret
= state
->reply_func(reply
);
3220 state
->num_failed
+= 1;
3225 state
->num_total
+= 1;
3226 if (state
->num_total
== state
->clist
->num
) {
3227 tevent_req_done(req
);
3231 static int process_clist_recv(struct tevent_req
*req
)
3233 struct process_clist_state
*state
= tevent_req_data(
3234 req
, struct process_clist_state
);
3236 return state
->num_failed
;
3239 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3240 int argc
, const char **argv
)
3242 struct ctdb_connection conn
;
3245 if (argc
!= 0 && argc
!= 2) {
3250 struct ctdb_connection_list
*clist
;
3251 struct tevent_req
*req
;
3253 /* Client first but the src/dst logic is confused */
3254 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3258 if (clist
->num
== 0) {
3262 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3263 ctdb_req_control_tcp_add_delayed_update
,
3264 ctdb_reply_control_tcp_add_delayed_update
);
3270 tevent_req_poll(req
, ctdb
->ev
);
3273 ret
= process_clist_recv(req
);
3275 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3282 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3284 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3287 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3289 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3293 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3294 ctdb
->client
, ctdb
->cmd_pnn
,
3297 fprintf(stderr
, "Failed to register connection\n");
3304 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3305 int argc
, const char **argv
)
3307 struct ctdb_connection conn
;
3310 if (argc
!= 0 && argc
!= 2) {
3315 struct ctdb_connection_list
*clist
;
3316 struct tevent_req
*req
;
3318 /* Client first but the src/dst logic is confused */
3319 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3323 if (clist
->num
== 0) {
3327 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3328 ctdb_req_control_tcp_remove
,
3329 ctdb_reply_control_tcp_remove
);
3335 tevent_req_poll(req
, ctdb
->ev
);
3338 ret
= process_clist_recv(req
);
3340 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3347 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3349 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3352 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3354 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3358 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3359 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3361 fprintf(stderr
, "Failed to unregister connection\n");
3368 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3369 int argc
, const char **argv
)
3371 struct ctdb_node_map
*nodemap
;
3378 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3379 if (nodemap
== NULL
) {
3383 for (i
=0; i
<nodemap
->num
; i
++) {
3384 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3388 if (options
.machinereadable
) {
3389 printf("%s%u%s%s%s\n", options
.sep
,
3390 nodemap
->node
[i
].pnn
, options
.sep
,
3391 ctdb_sock_addr_to_string(
3392 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3396 ctdb_sock_addr_to_string(
3397 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3404 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3405 struct ctdb_node_map
*nodemap2
)
3409 if (nodemap1
->num
!= nodemap2
->num
) {
3413 for (i
=0; i
<nodemap1
->num
; i
++) {
3414 struct ctdb_node_and_flags
*n1
, *n2
;
3416 n1
= &nodemap1
->node
[i
];
3417 n2
= &nodemap2
->node
[i
];
3419 if ((n1
->pnn
!= n2
->pnn
) ||
3420 (n1
->flags
!= n2
->flags
) ||
3421 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3429 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3430 struct ctdb_node_map
*nm
,
3431 struct ctdb_node_map
*fnm
,
3435 bool check_failed
= false;
3439 for (i
=0; i
<nm
->num
; i
++) {
3440 if (i
>= fnm
->num
) {
3442 "Node %u (%s) missing from nodes file\n",
3444 ctdb_sock_addr_to_string(
3445 mem_ctx
, &nm
->node
[i
].addr
, false));
3446 check_failed
= true;
3449 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3450 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3451 /* Node remains deleted */
3455 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3456 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3457 /* Node not newly nor previously deleted */
3458 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3459 &fnm
->node
[i
].addr
)) {
3461 "Node %u has changed IP address"
3462 " (was %s, now %s)\n",
3464 ctdb_sock_addr_to_string(
3466 &nm
->node
[i
].addr
, false),
3467 ctdb_sock_addr_to_string(
3469 &fnm
->node
[i
].addr
, false));
3470 check_failed
= true;
3472 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3474 "WARNING: Node %u is disconnected."
3475 " You MUST fix this node manually!\n",
3482 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3483 /* Node is being deleted */
3484 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3486 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3488 "ERROR: Node %u is still connected\n",
3490 check_failed
= true;
3495 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3496 /* Node was previously deleted */
3497 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3504 "ERROR: Nodes will not be reloaded due to previous error\n");
3508 /* Leftover nodes in file are NEW */
3509 for (; i
< fnm
->num
; i
++) {
3510 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3517 struct disable_recoveries_state
{
3525 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3528 struct disable_recoveries_state
*state
=
3529 (struct disable_recoveries_state
*)private_data
;
3532 if (data
.dsize
!= sizeof(int)) {
3537 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3538 ret
= *(int *)data
.dptr
;
3540 state
->status
= ret
;
3544 for (i
=0; i
<state
->node_count
; i
++) {
3545 if (state
->pnn_list
[i
] == ret
) {
3546 state
->reply
[i
] = true;
3552 for (i
=0; i
<state
->node_count
; i
++) {
3553 if (! state
->reply
[i
]) {
3554 state
->done
= false;
3560 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3561 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3563 struct ctdb_disable_message disable
= { 0 };
3564 struct disable_recoveries_state state
;
3567 disable
.pnn
= ctdb
->pnn
;
3568 disable
.srvid
= next_srvid(ctdb
);
3569 disable
.timeout
= timeout
;
3571 state
.pnn_list
= pnn_list
;
3572 state
.node_count
= count
;
3575 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3576 if (state
.reply
== NULL
) {
3580 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3582 disable_recoveries_handler
,
3588 for (i
=0; i
<count
; i
++) {
3589 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3598 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3600 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3602 ret
= (state
.status
>= 0 ? 0 : 1);
3606 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3607 disable
.srvid
, &state
);
3611 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3612 int argc
, const char **argv
)
3614 struct ctdb_node_map
*nodemap
= NULL
;
3615 struct ctdb_node_map
*file_nodemap
;
3616 struct ctdb_node_map
*remote_nodemap
;
3617 struct ctdb_req_control request
;
3618 struct ctdb_reply_control
**reply
;
3624 nodemap
= get_nodemap(ctdb
, false);
3625 if (nodemap
== NULL
) {
3629 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3630 if (file_nodemap
== NULL
) {
3634 for (i
=0; i
<nodemap
->num
; i
++) {
3635 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3639 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3640 nodemap
->node
[i
].pnn
, TIMEOUT(),
3644 "ERROR: Failed to get nodes file from node %u\n",
3645 nodemap
->node
[i
].pnn
);
3649 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3651 "ERROR: Nodes file on node %u differs"
3652 " from current node (%u)\n",
3653 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3658 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3664 fprintf(stderr
, "No change in nodes file,"
3665 " skipping unnecessary reload\n");
3669 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3670 mem_ctx
, &pnn_list
);
3672 fprintf(stderr
, "Memory allocation error\n");
3676 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3679 fprintf(stderr
, "Failed to disable recoveries\n");
3683 ctdb_req_control_reload_nodes_file(&request
);
3684 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3685 pnn_list
, count
, TIMEOUT(),
3686 &request
, NULL
, &reply
);
3688 bool failed
= false;
3690 for (i
=0; i
<count
; i
++) {
3691 ret
= ctdb_reply_control_reload_nodes_file(reply
[i
]);
3694 "Node %u failed to reload nodes\n",
3701 "You MUST fix failed nodes manually!\n");
3705 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3707 fprintf(stderr
, "Failed to enable recoveries\n");
3714 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3715 ctdb_sock_addr
*addr
, uint32_t pnn
)
3717 struct ctdb_public_ip_list
*pubip_list
;
3718 struct ctdb_public_ip pubip
;
3719 struct ctdb_node_map
*nodemap
;
3720 struct ctdb_req_control request
;
3724 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3725 CTDB_BROADCAST_CONNECTED
,
3726 2*options
.timelimit
);
3728 fprintf(stderr
, "Failed to disable IP check\n");
3732 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3733 pnn
, TIMEOUT(), false, &pubip_list
);
3735 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3740 for (i
=0; i
<pubip_list
->num
; i
++) {
3741 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3746 if (i
== pubip_list
->num
) {
3747 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3748 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3752 nodemap
= get_nodemap(ctdb
, false);
3753 if (nodemap
== NULL
) {
3757 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3759 fprintf(stderr
, "Memory allocation error\n");
3765 ctdb_req_control_release_ip(&request
, &pubip
);
3767 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3768 pnn_list
, count
, TIMEOUT(),
3769 &request
, NULL
, NULL
);
3771 fprintf(stderr
, "Failed to release IP on nodes\n");
3775 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3776 pnn
, TIMEOUT(), &pubip
);
3778 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3785 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3786 int argc
, const char **argv
)
3788 ctdb_sock_addr addr
;
3790 int ret
, retries
= 0;
3796 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3798 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3802 pnn
= strtoul(argv
[1], NULL
, 10);
3803 if (pnn
== CTDB_UNKNOWN_PNN
) {
3804 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3808 while (retries
< 5) {
3809 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3819 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3827 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3832 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3833 CTDB_BROADCAST_CONNECTED
, pnn
);
3836 "Failed to ask recovery master to distribute IPs\n");
3843 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3844 int argc
, const char **argv
)
3846 ctdb_sock_addr addr
;
3847 struct ctdb_public_ip_list
*pubip_list
;
3848 struct ctdb_addr_info addr_info
;
3850 int ret
, i
, retries
= 0;
3856 ret
= ctdb_sock_addr_mask_from_string(argv
[0], &addr
, &mask
);
3858 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3862 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3863 ctdb
->cmd_pnn
, TIMEOUT(),
3864 false, &pubip_list
);
3866 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3871 for (i
=0; i
<pubip_list
->num
; i
++) {
3872 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3873 fprintf(stderr
, "Node already knows about IP %s\n",
3874 ctdb_sock_addr_to_string(mem_ctx
,
3880 addr_info
.addr
= addr
;
3881 addr_info
.mask
= mask
;
3882 addr_info
.iface
= argv
[1];
3884 while (retries
< 5) {
3885 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3886 ctdb
->cmd_pnn
, TIMEOUT(),
3897 fprintf(stderr
, "Failed to add public IP to node %u."
3898 " Giving up\n", ctdb
->cmd_pnn
);
3902 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3910 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3911 int argc
, const char **argv
)
3913 ctdb_sock_addr addr
;
3914 struct ctdb_public_ip_list
*pubip_list
;
3915 struct ctdb_addr_info addr_info
;
3922 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3924 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3928 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3929 ctdb
->cmd_pnn
, TIMEOUT(),
3930 false, &pubip_list
);
3932 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3937 for (i
=0; i
<pubip_list
->num
; i
++) {
3938 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3943 if (i
== pubip_list
->num
) {
3944 fprintf(stderr
, "Node does not know about IP address %s\n",
3945 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
3949 addr_info
.addr
= addr
;
3951 addr_info
.iface
= NULL
;
3953 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3954 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
3956 fprintf(stderr
, "Failed to delete public IP from node %u\n",
3964 #define DB_VERSION 3
3965 #define MAX_DB_NAME 64
3966 #define MAX_REC_BUFFER_SIZE (100*1000)
3969 unsigned long version
;
3971 unsigned long flags
;
3974 char name
[MAX_DB_NAME
];
3977 struct backup_state
{
3978 TALLOC_CTX
*mem_ctx
;
3979 struct ctdb_rec_buffer
*recbuf
;
3982 unsigned int nbuf
, nrec
;
3985 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
3986 TDB_DATA key
, TDB_DATA data
, void *private_data
)
3988 struct backup_state
*state
= (struct backup_state
*)private_data
;
3992 if (state
->recbuf
== NULL
) {
3993 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
3995 if (state
->recbuf
== NULL
) {
4000 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4006 len
= ctdb_rec_buffer_len(state
->recbuf
);
4007 if (len
< MAX_REC_BUFFER_SIZE
) {
4011 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4013 fprintf(stderr
, "Failed to write records to backup file\n");
4018 state
->nrec
+= state
->recbuf
->count
;
4019 TALLOC_FREE(state
->recbuf
);
4024 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4025 int argc
, const char **argv
)
4027 const char *db_name
;
4028 struct ctdb_db_context
*db
;
4031 struct backup_state state
;
4032 struct db_header db_hdr
;
4039 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4043 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4046 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4050 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4053 fprintf(stderr
, "Failed to open file %s for writing\n",
4058 /* Write empty header first */
4059 ZERO_STRUCT(db_hdr
);
4060 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4064 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4068 state
.mem_ctx
= mem_ctx
;
4069 state
.recbuf
= NULL
;
4074 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4076 fprintf(stderr
, "Failed to collect records from DB %s\n",
4082 if (state
.recbuf
!= NULL
) {
4083 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4086 "Failed to write records to backup file\n");
4092 state
.nrec
+= state
.recbuf
->count
;
4093 TALLOC_FREE(state
.recbuf
);
4096 db_hdr
.version
= DB_VERSION
;
4097 db_hdr
.timestamp
= time(NULL
);
4098 db_hdr
.flags
= db_flags
;
4099 db_hdr
.nbuf
= state
.nbuf
;
4100 db_hdr
.nrec
= state
.nrec
;
4101 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4103 lseek(fd
, 0, SEEK_SET
);
4104 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4108 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4113 printf("Database backed up to %s\n", argv
[1]);
4117 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4118 int argc
, const char **argv
)
4120 const char *db_name
= NULL
;
4121 struct ctdb_db_context
*db
;
4122 struct db_header db_hdr
;
4123 struct ctdb_node_map
*nodemap
;
4124 struct ctdb_req_control request
;
4125 struct ctdb_reply_control
**reply
;
4126 struct ctdb_transdb wipedb
;
4127 struct ctdb_pulldb_ext pulldb
;
4128 struct ctdb_rec_buffer
*recbuf
;
4129 uint32_t generation
;
4137 if (argc
< 1 || argc
> 2) {
4141 fd
= open(argv
[0], O_RDONLY
, 0600);
4144 fprintf(stderr
, "Failed to open file %s for reading\n",
4153 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4157 fprintf(stderr
, "Failed to read db header from file %s\n",
4161 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4163 if (db_hdr
.version
!= DB_VERSION
) {
4165 "Wrong version of backup file, expected %u, got %lu\n",
4166 DB_VERSION
, db_hdr
.version
);
4171 if (db_name
== NULL
) {
4172 db_name
= db_hdr
.name
;
4175 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4176 localtime(&db_hdr
.timestamp
));
4177 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4179 db_flags
= db_hdr
.flags
& 0xff;
4180 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4183 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4188 nodemap
= get_nodemap(ctdb
, false);
4189 if (nodemap
== NULL
) {
4190 fprintf(stderr
, "Failed to get nodemap\n");
4195 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4197 fprintf(stderr
, "Failed to get current generation\n");
4202 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4209 wipedb
.db_id
= ctdb_db_id(db
);
4210 wipedb
.tid
= generation
;
4212 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4213 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4214 ctdb
->client
, pnn_list
, count
,
4215 TIMEOUT(), &request
, NULL
, NULL
);
4221 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4222 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4223 pnn_list
, count
, TIMEOUT(),
4224 &request
, NULL
, NULL
);
4229 ctdb_req_control_wipe_database(&request
, &wipedb
);
4230 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4231 pnn_list
, count
, TIMEOUT(),
4232 &request
, NULL
, NULL
);
4237 pulldb
.db_id
= ctdb_db_id(db
);
4239 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4241 ctdb_req_control_db_push_start(&request
, &pulldb
);
4242 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4243 pnn_list
, count
, TIMEOUT(),
4244 &request
, NULL
, NULL
);
4249 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4250 struct ctdb_req_message message
;
4254 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4259 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4260 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4261 if (data
.dptr
== NULL
) {
4265 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4267 message
.srvid
= pulldb
.srvid
;
4268 message
.data
.data
= data
;
4270 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4278 talloc_free(recbuf
);
4279 talloc_free(data
.dptr
);
4282 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4283 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4284 pnn_list
, count
, TIMEOUT(),
4285 &request
, NULL
, &reply
);
4290 for (i
=0; i
<count
; i
++) {
4291 uint32_t num_records
;
4293 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4296 fprintf(stderr
, "Invalid response from node %u\n",
4301 if (num_records
!= db_hdr
.nrec
) {
4302 fprintf(stderr
, "Node %u received %u of %lu records\n",
4303 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4308 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4309 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4310 pnn_list
, count
, TIMEOUT(),
4311 &request
, NULL
, NULL
);
4316 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4317 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4318 pnn_list
, count
, TIMEOUT(),
4319 &request
, NULL
, NULL
);
4324 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4325 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4326 ctdb
->client
, pnn_list
, count
,
4327 TIMEOUT(), &request
, NULL
, NULL
);
4332 printf("Database %s restored\n", db_name
);
4339 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4340 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4344 struct dumpdbbackup_state
{
4345 ctdb_rec_parser_func_t parser
;
4346 struct dump_record_state sub_state
;
4349 static int dumpdbbackup_handler(uint32_t reqid
,
4350 struct ctdb_ltdb_header
*header
,
4351 TDB_DATA key
, TDB_DATA data
,
4354 struct dumpdbbackup_state
*state
=
4355 (struct dumpdbbackup_state
*)private_data
;
4356 struct ctdb_ltdb_header hdr
;
4359 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4364 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4367 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4368 int argc
, const char **argv
)
4370 struct db_header db_hdr
;
4372 struct dumpdbbackup_state state
;
4377 usage("dumpbackup");
4380 fd
= open(argv
[0], O_RDONLY
, 0600);
4383 fprintf(stderr
, "Failed to open file %s for reading\n",
4388 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4392 fprintf(stderr
, "Failed to read db header from file %s\n",
4396 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4398 if (db_hdr
.version
!= DB_VERSION
) {
4400 "Wrong version of backup file, expected %u, got %lu\n",
4401 DB_VERSION
, db_hdr
.version
);
4406 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4407 localtime(&db_hdr
.timestamp
));
4408 printf("Dumping database %s from backup @ %s\n",
4409 db_hdr
.name
, timebuf
);
4411 state
.parser
= dump_record
;
4412 state
.sub_state
.count
= 0;
4414 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4415 struct ctdb_rec_buffer
*recbuf
;
4417 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4419 fprintf(stderr
, "Failed to read records\n");
4424 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4427 fprintf(stderr
, "Failed to dump records\n");
4434 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4438 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4439 int argc
, const char **argv
)
4441 const char *db_name
;
4442 struct ctdb_db_context
*db
;
4445 struct ctdb_node_map
*nodemap
;
4446 struct ctdb_req_control request
;
4447 struct ctdb_transdb wipedb
;
4448 uint32_t generation
;
4456 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4460 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4463 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4467 nodemap
= get_nodemap(ctdb
, false);
4468 if (nodemap
== NULL
) {
4469 fprintf(stderr
, "Failed to get nodemap\n");
4473 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4475 fprintf(stderr
, "Failed to get current generation\n");
4479 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4485 ctdb_req_control_db_freeze(&request
, db_id
);
4486 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4487 ctdb
->client
, pnn_list
, count
,
4488 TIMEOUT(), &request
, NULL
, NULL
);
4493 wipedb
.db_id
= db_id
;
4494 wipedb
.tid
= generation
;
4496 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4497 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4498 pnn_list
, count
, TIMEOUT(),
4499 &request
, NULL
, NULL
);
4504 ctdb_req_control_wipe_database(&request
, &wipedb
);
4505 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4506 pnn_list
, count
, TIMEOUT(),
4507 &request
, NULL
, NULL
);
4512 ctdb_req_control_db_set_healthy(&request
, db_id
);
4513 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4514 pnn_list
, count
, TIMEOUT(),
4515 &request
, NULL
, NULL
);
4520 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4521 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4522 pnn_list
, count
, TIMEOUT(),
4523 &request
, NULL
, NULL
);
4528 ctdb_req_control_db_thaw(&request
, db_id
);
4529 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4530 ctdb
->client
, pnn_list
, count
,
4531 TIMEOUT(), &request
, NULL
, NULL
);
4536 printf("Database %s wiped\n", db_name
);
4541 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4542 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4546 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4547 int argc
, const char **argv
)
4552 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4553 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4558 printf("%u\n", recmaster
);
4562 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4563 int argc
, const char **argv
)
4565 char *t
, *event_helper
= NULL
;
4567 t
= getenv("CTDB_EVENT_HELPER");
4569 event_helper
= talloc_strdup(mem_ctx
, t
);
4571 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb-event",
4572 CTDB_HELPER_BINDIR
);
4575 if (event_helper
== NULL
) {
4576 fprintf(stderr
, "Unable to set event daemon helper\n");
4580 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4584 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4585 int argc
, const char **argv
)
4587 const char *new_argv
[4];
4590 usage("scriptstatus");
4593 new_argv
[0] = "status";
4594 new_argv
[1] = "legacy";
4595 new_argv
[2] = (argc
== 0) ? "monitor" : argv
[0];
4598 (void) control_event(mem_ctx
, ctdb
, 3, new_argv
);
4602 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4603 int argc
, const char **argv
)
4605 char *t
, *natgw_helper
= NULL
;
4611 t
= getenv("CTDB_NATGW_HELPER");
4613 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4615 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4616 CTDB_HELPER_BINDIR
);
4619 if (natgw_helper
== NULL
) {
4620 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4624 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4629 * Find the PNN of the current node
4630 * discover the pnn by loading the nodes file and try to bind
4631 * to all addresses one at a time until the ip address is found.
4633 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4635 struct ctdb_node_map
*nodemap
;
4638 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4639 if (nodemap
== NULL
) {
4643 for (i
=0; i
<nodemap
->num
; i
++) {
4644 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4647 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4649 *pnn
= nodemap
->node
[i
].pnn
;
4651 talloc_free(nodemap
);
4656 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4657 talloc_free(nodemap
);
4661 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4662 int argc
, const char **argv
)
4664 const char *reclock
;
4668 usage("getreclock");
4671 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4672 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4677 if (reclock
!= NULL
) {
4678 printf("%s\n", reclock
);
4684 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4685 struct ctdb_context
*ctdb
,
4686 int argc
, const char **argv
)
4688 uint32_t lmasterrole
= 0;
4692 usage("setlmasterrole");
4695 if (strcmp(argv
[0], "on") == 0) {
4697 } else if (strcmp(argv
[0], "off") == 0) {
4700 usage("setlmasterrole");
4703 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4704 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4712 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4713 struct ctdb_context
*ctdb
,
4714 int argc
, const char **argv
)
4716 uint32_t recmasterrole
= 0;
4720 usage("setrecmasterrole");
4723 if (strcmp(argv
[0], "on") == 0) {
4725 } else if (strcmp(argv
[0], "off") == 0) {
4728 usage("setrecmasterrole");
4731 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4732 ctdb
->cmd_pnn
, TIMEOUT(),
4741 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4742 struct ctdb_context
*ctdb
,
4743 int argc
, const char **argv
)
4750 usage("setdbreadonly");
4753 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4757 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4758 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4762 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4763 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4771 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4772 int argc
, const char **argv
)
4779 usage("setdbsticky");
4782 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4786 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4787 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4791 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4792 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4800 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4801 int argc
, const char **argv
)
4803 const char *db_name
;
4804 struct ctdb_db_context
*db
;
4805 struct ctdb_transaction_handle
*h
;
4814 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4819 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4820 fprintf(stderr
, "Transactions not supported on DB %s\n",
4825 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4828 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4832 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4834 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4838 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4839 TIMEOUT(), db
, true, &h
);
4841 fprintf(stderr
, "Failed to start transaction on db %s\n",
4846 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4848 fprintf(stderr
, "Failed to read record for key %s\n",
4850 ctdb_transaction_cancel(h
);
4854 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4856 ctdb_transaction_cancel(h
);
4860 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4861 int argc
, const char **argv
)
4863 const char *db_name
;
4864 struct ctdb_db_context
*db
;
4865 struct ctdb_transaction_handle
*h
;
4874 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4879 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4880 fprintf(stderr
, "Transactions not supported on DB %s\n",
4885 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4888 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4892 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4894 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4898 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4900 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
4904 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4905 TIMEOUT(), db
, false, &h
);
4907 fprintf(stderr
, "Failed to start transaction on db %s\n",
4912 ret
= ctdb_transaction_store_record(h
, key
, data
);
4914 fprintf(stderr
, "Failed to store record for key %s\n",
4916 ctdb_transaction_cancel(h
);
4920 ret
= ctdb_transaction_commit(h
);
4922 fprintf(stderr
, "Failed to commit transaction on db %s\n",
4924 ctdb_transaction_cancel(h
);
4931 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4932 int argc
, const char **argv
)
4934 const char *db_name
;
4935 struct ctdb_db_context
*db
;
4936 struct ctdb_transaction_handle
*h
;
4945 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4950 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4951 fprintf(stderr
, "Transactions not supported on DB %s\n",
4956 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4959 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4963 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4965 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4969 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4970 TIMEOUT(), db
, false, &h
);
4972 fprintf(stderr
, "Failed to start transaction on db %s\n",
4977 ret
= ctdb_transaction_delete_record(h
, key
);
4979 fprintf(stderr
, "Failed to delete record for key %s\n",
4981 ctdb_transaction_cancel(h
);
4985 ret
= ctdb_transaction_commit(h
);
4987 fprintf(stderr
, "Failed to commit transaction on db %s\n",
4989 ctdb_transaction_cancel(h
);
4996 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5004 /* Skip whitespace */
5005 n
= strspn(*ptr
, " \t");
5009 /* Quoted ASCII string - no wide characters! */
5011 n
= strcspn(t
, "\"");
5014 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5021 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5025 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5032 #define MAX_LINE_SIZE 1024
5034 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5035 TDB_DATA
*key
, TDB_DATA
*value
)
5037 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5041 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5047 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5048 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5049 /* Line Ignored but not EOF */
5055 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5057 /* Line Ignored but not EOF */
5058 talloc_free(key
->dptr
);
5066 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5067 int argc
, const char **argv
)
5069 const char *db_name
;
5070 struct ctdb_db_context
*db
;
5071 struct ctdb_transaction_handle
*h
;
5074 TDB_DATA key
, value
;
5077 if (argc
< 1 || argc
> 2) {
5081 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5086 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5087 fprintf(stderr
, "Transactions not supported on DB %s\n",
5093 file
= fopen(argv
[1], "r");
5095 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5102 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5105 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5109 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5110 TIMEOUT(), db
, false, &h
);
5112 fprintf(stderr
, "Failed to start transaction on db %s\n",
5117 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5118 if (key
.dsize
!= 0) {
5119 ret
= ctdb_transaction_store_record(h
, key
, value
);
5121 fprintf(stderr
, "Failed to store record\n");
5122 ctdb_transaction_cancel(h
);
5125 talloc_free(key
.dptr
);
5126 talloc_free(value
.dptr
);
5130 ret
= ctdb_transaction_commit(h
);
5132 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5134 ctdb_transaction_cancel(h
);
5138 if (file
!= stdin
) {
5144 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5145 int argc
, const char **argv
)
5147 struct tdb_context
*tdb
;
5149 struct ctdb_ltdb_header header
;
5152 if (argc
< 2 || argc
> 3) {
5156 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5158 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5162 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5164 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5169 data
= tdb_fetch(tdb
, key
);
5170 if (data
.dptr
== NULL
) {
5171 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5176 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5177 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5188 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5190 fprintf(stderr
, "Failed to open output file %s\n",
5195 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5196 if (nwritten
!= data
.dsize
) {
5197 fprintf(stderr
, "Failed to write record to file\n");
5206 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5208 fprintf(stderr
, "Failed to parse header from data\n");
5212 dump_ltdb_header(&header
);
5213 dump_tdb_data("data", data
);
5218 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5219 int argc
, const char **argv
)
5221 struct tdb_context
*tdb
;
5222 TDB_DATA key
, data
[2], value
;
5223 struct ctdb_ltdb_header header
;
5224 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5228 if (argc
< 3 || argc
> 5) {
5232 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5234 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5238 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5240 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5245 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5247 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5252 ZERO_STRUCT(header
);
5255 header
.rsn
= (uint64_t)strtoull(argv
[3], NULL
, 0);
5258 header
.dmaster
= (uint32_t)atol(argv
[4]);
5261 header
.flags
= (uint32_t)atol(argv
[5]);
5264 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5267 data
[0].dptr
= header_buf
;
5269 data
[1].dsize
= value
.dsize
;
5270 data
[1].dptr
= value
.dptr
;
5272 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5274 fprintf(stderr
, "Failed to write record %s to file %s\n",
5283 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5284 int argc
, const char **argv
)
5286 const char *db_name
;
5287 struct ctdb_db_context
*db
;
5288 struct ctdb_record_handle
*h
;
5291 bool readonly
= false;
5294 if (argc
< 2 || argc
> 3) {
5299 if (strcmp(argv
[2], "readonly") == 0) {
5306 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5310 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5311 fprintf(stderr
, "DB %s is not a volatile database\n",
5316 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5319 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5323 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5325 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5329 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5330 db
, key
, readonly
, &h
, NULL
, &data
);
5332 fprintf(stderr
, "Failed to read record for key %s\n",
5335 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5336 (int)data
.dsize
, data
.dptr
);
5343 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5344 int argc
, const char **argv
)
5346 const char *db_name
;
5347 struct ctdb_db_context
*db
;
5348 struct ctdb_record_handle
*h
;
5357 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5361 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5362 fprintf(stderr
, "DB %s is not a volatile database\n",
5367 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5370 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5374 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5376 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5380 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5382 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5386 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5387 db
, key
, false, &h
, NULL
, NULL
);
5389 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5393 ret
= ctdb_store_record(h
, data
);
5395 fprintf(stderr
, "Failed to store record for key %s\n",
5403 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5404 int argc
, const char **argv
)
5406 const char *db_name
;
5407 struct ctdb_db_context
*db
;
5408 struct ctdb_record_handle
*h
;
5417 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5421 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5422 fprintf(stderr
, "DB %s is not a volatile database\n",
5427 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5430 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5434 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5436 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5440 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5441 db
, key
, false, &h
, NULL
, &data
);
5443 fprintf(stderr
, "Failed to fetch record for key %s\n",
5448 ret
= ctdb_delete_record(h
);
5450 fprintf(stderr
, "Failed to delete record for key %s\n",
5458 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5459 int argc
, const char **argv
)
5461 struct sockaddr_in sin
;
5467 usage("chktcpport");
5470 port
= atoi(argv
[0]);
5472 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5474 fprintf(stderr
, "Failed to open local socket\n");
5478 v
= fcntl(s
, F_GETFL
, 0);
5479 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5480 fprintf(stderr
, "Unable to set socket non-blocking\n");
5485 bzero(&sin
, sizeof(sin
));
5486 sin
.sin_family
= AF_INET
;
5487 sin
.sin_port
= htons(port
);
5488 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5491 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5498 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5499 int argc
, const char **argv
)
5502 const char *db_name
;
5507 usage("getdbseqnum");
5510 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5514 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5515 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5518 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5523 printf("0x%"PRIx64
"\n", seqnum
);
5527 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5528 int argc
, const char **argv
)
5530 const char *nodestring
= NULL
;
5531 struct ctdb_node_map
*nodemap
;
5533 bool print_hdr
= false;
5536 usage("nodestatus");
5540 nodestring
= argv
[0];
5541 if (strcmp(nodestring
, "all") == 0) {
5546 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5550 if (options
.machinereadable
) {
5551 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5553 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5557 for (i
=0; i
<nodemap
->num
; i
++) {
5558 ret
|= nodemap
->node
[i
].flags
;
5567 } db_stats_fields
[] = {
5568 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5569 DBSTATISTICS_FIELD(db_ro_delegations
),
5570 DBSTATISTICS_FIELD(db_ro_revokes
),
5571 DBSTATISTICS_FIELD(locks
.num_calls
),
5572 DBSTATISTICS_FIELD(locks
.num_current
),
5573 DBSTATISTICS_FIELD(locks
.num_pending
),
5574 DBSTATISTICS_FIELD(locks
.num_failed
),
5577 static void print_dbstatistics(const char *db_name
,
5578 struct ctdb_db_statistics
*s
)
5581 const char *prefix
= NULL
;
5584 printf("DB Statistics %s\n", db_name
);
5586 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5587 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5588 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5590 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5591 prefix
= db_stats_fields
[i
].name
;
5592 printf(" %*.*s\n", preflen
-1, preflen
-1,
5593 db_stats_fields
[i
].name
);
5598 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5599 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5600 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5603 printf(" hop_count_buckets:");
5604 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5605 printf(" %d", s
->hop_count_bucket
[i
]);
5609 printf(" lock_buckets:");
5610 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5611 printf(" %d", s
->locks
.buckets
[i
]);
5615 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5616 "locks_latency MIN/AVG/MAX",
5617 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5618 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5620 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5621 "vacuum_latency MIN/AVG/MAX",
5622 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5623 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5625 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5626 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5628 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5629 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5630 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5636 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5637 int argc
, const char **argv
)
5640 const char *db_name
;
5641 struct ctdb_db_statistics
*dbstats
;
5645 usage("dbstatistics");
5648 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5652 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5653 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5656 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5661 print_dbstatistics(db_name
, dbstats
);
5665 struct disable_takeover_runs_state
{
5673 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5676 struct disable_takeover_runs_state
*state
=
5677 (struct disable_takeover_runs_state
*)private_data
;
5680 if (data
.dsize
!= sizeof(int)) {
5685 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5686 ret
= *(int *)data
.dptr
;
5688 state
->status
= ret
;
5692 for (i
=0; i
<state
->node_count
; i
++) {
5693 if (state
->pnn_list
[i
] == ret
) {
5694 state
->reply
[i
] = true;
5700 for (i
=0; i
<state
->node_count
; i
++) {
5701 if (! state
->reply
[i
]) {
5702 state
->done
= false;
5708 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5709 struct ctdb_context
*ctdb
, uint32_t timeout
,
5710 uint32_t *pnn_list
, int count
)
5712 struct ctdb_disable_message disable
= { 0 };
5713 struct disable_takeover_runs_state state
;
5716 disable
.pnn
= ctdb
->pnn
;
5717 disable
.srvid
= next_srvid(ctdb
);
5718 disable
.timeout
= timeout
;
5720 state
.pnn_list
= pnn_list
;
5721 state
.node_count
= count
;
5724 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5725 if (state
.reply
== NULL
) {
5729 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5731 disable_takeover_run_handler
,
5737 for (i
=0; i
<count
; i
++) {
5738 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5747 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5749 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5751 ret
= (state
.status
>= 0 ? 0 : 1);
5755 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5756 disable
.srvid
, &state
);
5760 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5761 int argc
, const char **argv
)
5763 const char *nodestring
= NULL
;
5764 struct ctdb_node_map
*nodemap
, *nodemap2
;
5765 struct ctdb_req_control request
;
5766 uint32_t *pnn_list
, *pnn_list2
;
5767 int ret
, count
, count2
;
5774 nodestring
= argv
[0];
5777 nodemap
= get_nodemap(ctdb
, false);
5778 if (nodemap
== NULL
) {
5782 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5786 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5787 mem_ctx
, &pnn_list
);
5789 fprintf(stderr
, "Memory allocation error\n");
5793 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5794 mem_ctx
, &pnn_list2
);
5796 fprintf(stderr
, "Memory allocation error\n");
5800 /* Disable takeover runs on all connected nodes. A reply
5801 * indicating success is needed from each node so all nodes
5802 * will need to be active.
5804 * A check could be added to not allow reloading of IPs when
5805 * there are disconnected nodes. However, this should
5806 * probably be left up to the administrator.
5808 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5811 fprintf(stderr
, "Failed to disable takeover runs\n");
5815 /* Now tell all the desired nodes to reload their public IPs.
5816 * Keep trying this until it succeeds. This assumes all
5817 * failures are transient, which might not be true...
5819 ctdb_req_control_reload_public_ips(&request
);
5820 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5821 pnn_list2
, count2
, TIMEOUT(),
5822 &request
, NULL
, NULL
);
5824 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5827 /* It isn't strictly necessary to wait until takeover runs are
5828 * re-enabled but doing so can't hurt.
5830 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5832 fprintf(stderr
, "Failed to enable takeover runs\n");
5836 return ipreallocate(mem_ctx
, ctdb
);
5840 static const struct ctdb_cmd
{
5842 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5843 bool without_daemon
; /* can be run without daemon running ? */
5844 bool remote
; /* can be run on remote nodes */
5847 } ctdb_commands
[] = {
5848 { "version", control_version
, true, false,
5849 "show version of ctdb", NULL
},
5850 { "status", control_status
, false, true,
5851 "show node status", NULL
},
5852 { "uptime", control_uptime
, false, true,
5853 "show node uptime", NULL
},
5854 { "ping", control_ping
, false, true,
5855 "ping a node", NULL
},
5856 { "runstate", control_runstate
, false, true,
5857 "get/check runstate of a node",
5858 "[setup|first_recovery|startup|running]" },
5859 { "getvar", control_getvar
, false, true,
5860 "get a tunable variable", "<name>" },
5861 { "setvar", control_setvar
, false, true,
5862 "set a tunable variable", "<name> <value>" },
5863 { "listvars", control_listvars
, false, true,
5864 "list tunable variables", NULL
},
5865 { "statistics", control_statistics
, false, true,
5866 "show ctdb statistics", NULL
},
5867 { "statisticsreset", control_statistics_reset
, false, true,
5868 "reset ctdb statistics", NULL
},
5869 { "stats", control_stats
, false, true,
5870 "show rolling statistics", "[count]" },
5871 { "ip", control_ip
, false, true,
5872 "show public ips", "[all]" },
5873 { "ipinfo", control_ipinfo
, false, true,
5874 "show public ip details", "<ip>" },
5875 { "ifaces", control_ifaces
, false, true,
5876 "show interfaces", NULL
},
5877 { "setifacelink", control_setifacelink
, false, true,
5878 "set interface link status", "<iface> up|down" },
5879 { "process-exists", control_process_exists
, false, true,
5880 "check if a process exists on a node", "<pid> [<srvid>]" },
5881 { "getdbmap", control_getdbmap
, false, true,
5882 "show attached databases", NULL
},
5883 { "getdbstatus", control_getdbstatus
, false, true,
5884 "show database status", "<dbname|dbid>" },
5885 { "catdb", control_catdb
, false, false,
5886 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5887 { "cattdb", control_cattdb
, false, false,
5888 "dump local ctdb database", "<dbname|dbid>" },
5889 { "getcapabilities", control_getcapabilities
, false, true,
5890 "show node capabilities", NULL
},
5891 { "pnn", control_pnn
, false, false,
5892 "show the pnn of the currnet node", NULL
},
5893 { "lvs", control_lvs
, false, false,
5894 "show lvs configuration", "master|list|status" },
5895 { "setdebug", control_setdebug
, false, true,
5896 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5897 { "getdebug", control_getdebug
, false, true,
5898 "get debug level", NULL
},
5899 { "attach", control_attach
, false, false,
5900 "attach a database", "<dbname> [persistent|replicated]" },
5901 { "detach", control_detach
, false, false,
5902 "detach database(s)", "<dbname|dbid> ..." },
5903 { "dumpmemory", control_dumpmemory
, false, true,
5904 "dump ctdbd memory map", NULL
},
5905 { "rddumpmemory", control_rddumpmemory
, false, true,
5906 "dump recoverd memory map", NULL
},
5907 { "getpid", control_getpid
, false, true,
5908 "get ctdbd process ID", NULL
},
5909 { "disable", control_disable
, false, true,
5910 "disable a node", NULL
},
5911 { "enable", control_enable
, false, true,
5912 "enable a node", NULL
},
5913 { "stop", control_stop
, false, true,
5914 "stop a node", NULL
},
5915 { "continue", control_continue
, false, true,
5916 "continue a stopped node", NULL
},
5917 { "ban", control_ban
, false, true,
5918 "ban a node", "<bantime>"},
5919 { "unban", control_unban
, false, true,
5920 "unban a node", NULL
},
5921 { "shutdown", control_shutdown
, false, true,
5922 "shutdown ctdb daemon", NULL
},
5923 { "recover", control_recover
, false, true,
5924 "force recovery", NULL
},
5925 { "sync", control_ipreallocate
, false, true,
5926 "run ip reallocation (deprecated)", NULL
},
5927 { "ipreallocate", control_ipreallocate
, false, true,
5928 "run ip reallocation", NULL
},
5929 { "isnotrecmaster", control_isnotrecmaster
, false, false,
5930 "check if local node is the recmaster", NULL
},
5931 { "gratarp", control_gratarp
, false, true,
5932 "send a gratuitous arp", "<ip> <interface>" },
5933 { "tickle", control_tickle
, true, false,
5934 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5935 { "gettickles", control_gettickles
, false, true,
5936 "get the list of tickles", "<ip> [<port>]" },
5937 { "addtickle", control_addtickle
, false, true,
5938 "add a tickle", "<ip>:<port> <ip>:<port>" },
5939 { "deltickle", control_deltickle
, false, true,
5940 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5941 { "listnodes", control_listnodes
, true, true,
5942 "list nodes in the cluster", NULL
},
5943 { "reloadnodes", control_reloadnodes
, false, false,
5944 "reload the nodes file all nodes", NULL
},
5945 { "moveip", control_moveip
, false, false,
5946 "move an ip address to another node", "<ip> <node>" },
5947 { "addip", control_addip
, false, true,
5948 "add an ip address to a node", "<ip/mask> <iface>" },
5949 { "delip", control_delip
, false, true,
5950 "delete an ip address from a node", "<ip>" },
5951 { "backupdb", control_backupdb
, false, false,
5952 "backup a database into a file", "<dbname|dbid> <file>" },
5953 { "restoredb", control_restoredb
, false, false,
5954 "restore a database from a file", "<file> [dbname]" },
5955 { "dumpdbbackup", control_dumpdbbackup
, true, false,
5956 "dump database from a backup file", "<file>" },
5957 { "wipedb", control_wipedb
, false, false,
5958 "wipe the contents of a database.", "<dbname|dbid>"},
5959 { "recmaster", control_recmaster
, false, true,
5960 "show the pnn for the recovery master", NULL
},
5961 { "event", control_event
, true, false,
5962 "event and event script commands", NULL
},
5963 { "scriptstatus", control_scriptstatus
, true, false,
5964 "show event script status",
5965 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5966 { "natgw", control_natgw
, false, false,
5967 "show natgw configuration", "master|list|status" },
5968 { "getreclock", control_getreclock
, false, true,
5969 "get recovery lock file", NULL
},
5970 { "setlmasterrole", control_setlmasterrole
, false, true,
5971 "set LMASTER role", "on|off" },
5972 { "setrecmasterrole", control_setrecmasterrole
, false, true,
5973 "set RECMASTER role", "on|off"},
5974 { "setdbreadonly", control_setdbreadonly
, false, true,
5975 "enable readonly records", "<dbname|dbid>" },
5976 { "setdbsticky", control_setdbsticky
, false, true,
5977 "enable sticky records", "<dbname|dbid>"},
5978 { "pfetch", control_pfetch
, false, false,
5979 "fetch record from persistent database", "<dbname|dbid> <key>" },
5980 { "pstore", control_pstore
, false, false,
5981 "write record to persistent database", "<dbname|dbid> <key> <value>" },
5982 { "pdelete", control_pdelete
, false, false,
5983 "delete record from persistent database", "<dbname|dbid> <key>" },
5984 { "ptrans", control_ptrans
, false, false,
5985 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
5986 { "tfetch", control_tfetch
, false, true,
5987 "fetch a record", "<tdb-file> <key> [<file>]" },
5988 { "tstore", control_tstore
, false, true,
5989 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
5990 { "readkey", control_readkey
, false, false,
5991 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
5992 { "writekey", control_writekey
, false, false,
5993 "write value for a database key", "<dbname|dbid> <key> <value>" },
5994 { "deletekey", control_deletekey
, false, false,
5995 "delete a database key", "<dbname|dbid> <key>" },
5996 { "checktcpport", control_checktcpport
, true, false,
5997 "check if a service is bound to a specific tcp port or not", "<port>" },
5998 { "getdbseqnum", control_getdbseqnum
, false, false,
5999 "get database sequence number", "<dbname|dbid>" },
6000 { "nodestatus", control_nodestatus
, false, true,
6001 "show and return node status", "[all|<pnn-list>]" },
6002 { "dbstatistics", control_dbstatistics
, false, true,
6003 "show database statistics", "<dbname|dbid>" },
6004 { "reloadips", control_reloadips
, false, false,
6005 "reload the public addresses file", "[all|<pnn-list>]" },
6008 static const struct ctdb_cmd
*match_command(const char *command
)
6010 const struct ctdb_cmd
*cmd
;
6013 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6014 cmd
= &ctdb_commands
[i
];
6015 if (strlen(command
) == strlen(cmd
->name
) &&
6016 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6026 * Show usage message
6028 static void usage_full(void)
6032 poptPrintHelp(pc
, stdout
, 0);
6033 printf("\nCommands:\n");
6034 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6035 printf(" %-15s %-27s %s\n",
6036 ctdb_commands
[i
].name
,
6037 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6038 ctdb_commands
[i
].msg
);
6042 static void usage(const char *command
)
6044 const struct ctdb_cmd
*cmd
;
6046 if (command
== NULL
) {
6051 cmd
= match_command(command
);
6055 poptPrintUsage(pc
, stdout
, 0);
6056 printf("\nCommands:\n");
6057 printf(" %-15s %-27s %s\n",
6058 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6064 struct poptOption cmdline_options
[] = {
6066 { "debug", 'd', POPT_ARG_STRING
, &options
.debuglevelstr
, 0,
6068 { "timelimit", 't', POPT_ARG_INT
, &options
.timelimit
, 0,
6069 "timelimit (in seconds)" },
6070 { "node", 'n', POPT_ARG_INT
, &options
.pnn
, 0,
6071 "node specification - integer" },
6072 { NULL
, 'Y', POPT_ARG_NONE
, &options
.machinereadable
, 0,
6073 "enable machine readable output", NULL
},
6074 { "separator", 'x', POPT_ARG_STRING
, &options
.sep
, 0,
6075 "specify separator for machine readable output", "CHAR" },
6076 { NULL
, 'X', POPT_ARG_NONE
, &options
.machineparsable
, 0,
6077 "enable machine parsable output with separator |", NULL
},
6078 { "verbose", 'v', POPT_ARG_NONE
, &options
.verbose
, 0,
6079 "enable verbose output", NULL
},
6080 { "maxruntime", 'T', POPT_ARG_INT
, &options
.maxruntime
, 0,
6081 "die if runtime exceeds this limit (in seconds)" },
6085 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6088 TALLOC_CTX
*tmp_ctx
;
6089 struct ctdb_context
*ctdb
;
6090 const char *ctdb_socket
;
6093 uint64_t srvid_offset
;
6095 tmp_ctx
= talloc_new(NULL
);
6096 if (tmp_ctx
== NULL
) {
6097 fprintf(stderr
, "Memory allocation error\n");
6101 if (cmd
->without_daemon
) {
6102 if (options
.pnn
!= -1) {
6104 "Cannot specify node for command %s\n",
6109 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6110 talloc_free(tmp_ctx
);
6114 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6116 fprintf(stderr
, "Memory allocation error\n");
6120 ctdb
->ev
= tevent_context_init(ctdb
);
6121 if (ctdb
->ev
== NULL
) {
6122 fprintf(stderr
, "Failed to initialize tevent\n");
6126 ctdb_socket
= path_socket(ctdb
, "ctdbd");
6127 if (ctdb_socket
== NULL
) {
6128 fprintf(stderr
, "Memory allocation error\n");
6132 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6134 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6137 if (!find_node_xpnn(ctdb
, NULL
)) {
6138 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6143 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6144 srvid_offset
= getpid() & 0xFFFF;
6145 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6147 if (options
.pnn
!= -1) {
6148 status
= verify_pnn(ctdb
, options
.pnn
);
6153 ctdb
->cmd_pnn
= options
.pnn
;
6155 ctdb
->cmd_pnn
= ctdb
->pnn
;
6158 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6159 fprintf(stderr
, "Node cannot be specified for command %s\n",
6164 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6165 talloc_free(tmp_ctx
);
6169 talloc_free(tmp_ctx
);
6173 static void signal_handler(int sig
)
6175 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6178 static void alarm_handler(int sig
)
6180 /* Kill any child processes */
6181 signal(SIGTERM
, signal_handler
);
6187 int main(int argc
, const char *argv
[])
6190 const char **extra_argv
;
6192 const struct ctdb_cmd
*cmd
;
6199 /* Set default options */
6200 options
.debuglevelstr
= NULL
;
6201 options
.timelimit
= 10;
6203 options
.maxruntime
= 0;
6206 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6207 POPT_CONTEXT_KEEP_FIRST
);
6208 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6209 fprintf(stderr
, "Invalid option %s: %s\n",
6210 poptBadOption(pc
, 0), poptStrerror(opt
));
6214 if (options
.maxruntime
== 0) {
6215 const char *ctdb_timeout
;
6217 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6218 if (ctdb_timeout
!= NULL
) {
6219 options
.maxruntime
= strtoul(ctdb_timeout
, NULL
, 0);
6221 options
.maxruntime
= 120;
6224 if (options
.maxruntime
<= 120) {
6225 /* default timeout is 120 seconds */
6226 options
.maxruntime
= 120;
6229 if (options
.machineparsable
) {
6230 options
.machinereadable
= 1;
6233 /* setup the remaining options for the commands */
6235 extra_argv
= poptGetArgs(pc
);
6238 while (extra_argv
[extra_argc
]) extra_argc
++;
6241 if (extra_argc
< 1) {
6245 cmd
= match_command(extra_argv
[0]);
6247 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6251 /* Enable logging */
6252 setup_logging("ctdb", DEBUG_STDERR
);
6253 ok
= debug_level_parse(options
.debuglevelstr
, &loglevel
);
6255 loglevel
= DEBUG_ERR
;
6257 debuglevel_set(loglevel
);
6259 signal(SIGALRM
, alarm_handler
);
6260 alarm(options
.maxruntime
);
6262 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6267 (void)poptFreeContext(pc
);