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"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
37 #include "lib/util/smb_strtox.h"
39 #include "common/db_hash.h"
40 #include "common/logging.h"
41 #include "common/path.h"
42 #include "protocol/protocol.h"
43 #include "protocol/protocol_basic.h"
44 #include "protocol/protocol_api.h"
45 #include "protocol/protocol_util.h"
46 #include "common/system_socket.h"
47 #include "client/client.h"
48 #include "client/client_sync.h"
50 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
52 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
53 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
55 #define NODE_FLAGS_UNKNOWN 0x00000040
58 const char *debuglevelstr
;
66 int printemptyrecords
;
73 static poptContext pc
;
76 struct tevent_context
*ev
;
77 struct ctdb_client_context
*client
;
78 struct ctdb_node_map
*nodemap
;
79 uint32_t pnn
, cmd_pnn
, leader_pnn
;
83 static void usage(const char *command
);
89 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
91 return (tv2
->tv_sec
- tv
->tv_sec
) +
92 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
95 static struct ctdb_node_and_flags
*get_node_by_pnn(
96 struct ctdb_node_map
*nodemap
,
101 for (i
=0; i
<nodemap
->num
; i
++) {
102 if (nodemap
->node
[i
].pnn
== pnn
) {
103 return &nodemap
->node
[i
];
109 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
111 static const struct {
115 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
116 { NODE_FLAGS_UNKNOWN
, "UNKNOWN" },
117 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
118 { NODE_FLAGS_BANNED
, "BANNED" },
119 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
120 { NODE_FLAGS_DELETED
, "DELETED" },
121 { NODE_FLAGS_STOPPED
, "STOPPED" },
122 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
124 char *flags_str
= NULL
;
127 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
128 if (flags
& flag_names
[i
].flag
) {
129 if (flags_str
== NULL
) {
130 flags_str
= talloc_asprintf(mem_ctx
,
131 "%s", flag_names
[i
].name
);
133 flags_str
= talloc_asprintf_append(flags_str
,
134 "|%s", flag_names
[i
].name
);
136 if (flags_str
== NULL
) {
137 return "OUT-OF-MEMORY";
141 if (flags_str
== NULL
) {
148 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
155 * Get consistent nodemap information.
157 * If nodemap is already cached, use that. If not get it.
158 * If the current node is BANNED, then get nodemap from "better" node.
160 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
163 struct ctdb_node_map
*nodemap
;
164 struct ctdb_node_and_flags
*node
;
165 uint32_t current_node
;
169 TALLOC_FREE(ctdb
->nodemap
);
172 if (ctdb
->nodemap
!= NULL
) {
173 return ctdb
->nodemap
;
176 tmp_ctx
= talloc_new(ctdb
);
177 if (tmp_ctx
== NULL
) {
181 current_node
= ctdb
->pnn
;
183 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
184 current_node
, TIMEOUT(), &nodemap
);
186 fprintf(stderr
, "Failed to get nodemap from node %u\n",
191 node
= get_node_by_pnn(nodemap
, current_node
);
192 if (node
->flags
& NODE_FLAGS_BANNED
) {
195 current_node
= (current_node
+ 1) % nodemap
->num
;
196 node
= get_node_by_pnn(nodemap
, current_node
);
198 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
201 } while (current_node
!= ctdb
->pnn
);
203 if (current_node
== ctdb
->pnn
) {
204 /* Tried all nodes in the cluster */
205 fprintf(stderr
, "Warning: All nodes are banned.\n");
212 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
216 talloc_free(tmp_ctx
);
220 static void print_pnn(uint32_t pnn
)
222 if (pnn
== CTDB_UNKNOWN_PNN
) {
230 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
232 struct ctdb_node_map
*nodemap
;
240 nodemap
= get_nodemap(ctdb
, false);
241 if (nodemap
== NULL
) {
246 for (i
=0; i
<nodemap
->num
; i
++) {
247 if (nodemap
->node
[i
].pnn
== (uint32_t)pnn
) {
253 fprintf(stderr
, "Node %u does not exist\n", pnn
);
257 if (nodemap
->node
[i
].flags
&
258 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
259 fprintf(stderr
, "Node %u has status %s\n", pnn
,
260 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
267 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
268 struct ctdb_node_map
*nodemap
)
270 struct ctdb_node_map
*nodemap2
;
272 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
273 if (nodemap2
== NULL
) {
277 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
279 if (nodemap2
->node
== NULL
) {
280 talloc_free(nodemap2
);
288 * Get the number and the list of matching nodes
290 * nodestring := NULL | all | pnn,[pnn,...]
292 * If nodestring is NULL, use the current node.
294 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
295 const char *nodestring
,
296 struct ctdb_node_map
**out
)
298 struct ctdb_node_map
*nodemap
, *nodemap2
;
299 struct ctdb_node_and_flags
*node
;
302 nodemap
= get_nodemap(ctdb
, false);
303 if (nodemap
== NULL
) {
307 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
308 if (nodemap2
== NULL
) {
312 if (nodestring
== NULL
) {
313 for (i
=0; i
<nodemap
->num
; i
++) {
314 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
315 nodemap2
->node
[0] = nodemap
->node
[i
];
324 if (strcmp(nodestring
, "all") == 0) {
325 for (i
=0; i
<nodemap
->num
; i
++) {
326 nodemap2
->node
[i
] = nodemap
->node
[i
];
328 nodemap2
->num
= nodemap
->num
;
335 ns
= talloc_strdup(mem_ctx
, nodestring
);
340 tok
= strtok(ns
, ",");
341 while (tok
!= NULL
) {
344 pnn
= (uint32_t)smb_strtoul(tok
,
350 fprintf(stderr
, "Invalid node %s\n", tok
);
354 node
= get_node_by_pnn(nodemap
, pnn
);
356 fprintf(stderr
, "Node %u does not exist\n",
361 nodemap2
->node
[nodemap2
->num
] = *node
;
364 tok
= strtok(NULL
, ",");
374 * Remote nodes are initialised as UNHEALTHY in the daemon and their
375 * true status is updated after they are connected. However, there
376 * is a small window when a healthy node may be shown as unhealthy
377 * between connecting and the status update. Hide this for nodes
378 * that are not DISCONNECTED nodes by reporting them as UNKNOWN until
379 * the runstate passes FIRST_RECOVERY. Code paths where this is used
380 * do not make any control decisions depending upon unknown/unhealthy
383 static struct ctdb_node_map
*get_nodemap_unknown(
385 struct ctdb_context
*ctdb
,
386 struct ctdb_node_map
*nodemap_in
)
390 enum ctdb_runstate runstate
;
391 struct ctdb_node_map
*nodemap
;
393 ret
= ctdb_ctrl_get_runstate(mem_ctx
,
400 printf("Unable to get runstate");
404 nodemap
= talloc_nodemap(mem_ctx
, nodemap_in
);
405 if (nodemap
== NULL
) {
406 printf("Unable to get nodemap");
410 nodemap
->num
= nodemap_in
->num
;
411 for (i
=0; i
<nodemap
->num
; i
++) {
412 struct ctdb_node_and_flags
*node_in
= &nodemap_in
->node
[i
];
413 struct ctdb_node_and_flags
*node
= &nodemap
->node
[i
];
417 if (node
->flags
& NODE_FLAGS_DELETED
) {
421 if ((runstate
<= CTDB_RUNSTATE_FIRST_RECOVERY
) &&
422 !(node
->flags
& NODE_FLAGS_DISCONNECTED
) &&
423 (node
->pnn
!= ctdb
->cmd_pnn
)) {
424 node
->flags
= NODE_FLAGS_UNKNOWN
;
431 /* Compare IP address */
432 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
436 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
440 switch (ip1
->sa
.sa_family
) {
442 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
443 sizeof(struct in_addr
)) == 0);
447 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
448 sizeof(struct in6_addr
)) == 0);
455 /* Append a node to a node map with given address and flags */
456 static bool node_map_add(struct ctdb_node_map
*nodemap
,
457 const char *nstr
, uint32_t flags
)
461 struct ctdb_node_and_flags
*n
;
464 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
466 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
471 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
472 struct ctdb_node_and_flags
, num
+1);
473 if (nodemap
->node
== NULL
) {
477 n
= &nodemap
->node
[num
];
482 nodemap
->num
= num
+1;
486 /* Read a nodes file into a node map */
487 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
493 struct ctdb_node_map
*nodemap
;
495 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
496 if (nodemap
== NULL
) {
500 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
505 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
509 for (i
=0; i
<nlines
; i
++) {
515 /* strip leading spaces */
516 while((*node
== ' ') || (*node
== '\t')) {
522 /* strip trailing spaces */
524 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
534 /* A "deleted" node is a node that is
535 commented out in the nodes file. This is
536 used instead of removing a line, which
537 would cause subsequent nodes to change
539 flags
= NODE_FLAGS_DELETED
;
540 node
= discard_const("0.0.0.0");
544 if (! node_map_add(nodemap
, node
, flags
)) {
546 TALLOC_FREE(nodemap
);
555 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
557 struct ctdb_node_map
*nodemap
;
558 const char *nodes_list
= NULL
;
560 const char *basedir
= getenv("CTDB_BASE");
561 if (basedir
== NULL
) {
562 basedir
= CTDB_ETCDIR
;
564 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
565 if (nodes_list
== NULL
) {
566 fprintf(stderr
, "Memory allocation error\n");
570 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
571 if (nodemap
== NULL
) {
572 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
580 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
581 struct ctdb_context
*ctdb
,
582 struct ctdb_dbid_map
*dbmap
,
585 struct ctdb_dbid
*db
= NULL
;
590 for (i
=0; i
<dbmap
->num
; i
++) {
591 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
592 ctdb
->pnn
, TIMEOUT(),
593 dbmap
->dbs
[i
].db_id
, &name
);
598 if (strcmp(db_name
, name
) == 0) {
599 talloc_free(discard_const(name
));
608 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
609 const char *db_arg
, uint32_t *db_id
,
610 const char **db_name
, uint8_t *db_flags
)
612 struct ctdb_dbid_map
*dbmap
;
613 struct ctdb_dbid
*db
= NULL
;
615 const char *name
= NULL
;
619 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
620 ctdb
->pnn
, TIMEOUT(), &dbmap
);
625 if (strncmp(db_arg
, "0x", 2) == 0) {
626 id
= smb_strtoul(db_arg
, NULL
, 0, &ret
, SMB_STR_STANDARD
);
630 for (i
=0; i
<dbmap
->num
; i
++) {
631 if (id
== dbmap
->dbs
[i
].db_id
) {
638 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
642 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
647 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
648 ctdb
->pnn
, TIMEOUT(), id
, &name
);
657 if (db_name
!= NULL
) {
658 *db_name
= talloc_strdup(mem_ctx
, name
);
660 if (db_flags
!= NULL
) {
661 *db_flags
= db
->flags
;
666 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
673 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
678 data
.dsize
= len
/ 2;
679 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
680 if (data
.dptr
== NULL
) {
684 for (i
=0; i
<data
.dsize
; i
++) {
685 bool ok
= hex_byte(&str
[i
*2], &data
.dptr
[i
]);
687 fprintf(stderr
, "Invalid hex: %s\n", &str
[i
*2]);
696 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
702 if (strncmp(str
, "0x", 2) == 0) {
703 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
708 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
709 if (data
.dptr
== NULL
) {
719 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
720 const char *path
, int argc
, const char **argv
)
723 int save_errno
, status
, ret
;
724 const char **new_argv
;
727 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
728 if (new_argv
== NULL
) {
733 for (i
=0; i
<argc
; i
++) {
734 new_argv
[i
+1] = argv
[i
];
736 new_argv
[argc
+1] = NULL
;
741 talloc_free(new_argv
);
742 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
743 command
, path
, strerror(save_errno
));
748 ret
= execv(path
, discard_const(new_argv
));
752 /* Should not happen */
756 talloc_free(new_argv
);
758 ret
= waitpid(pid
, &status
, 0);
761 fprintf(stderr
, "waitpid() failed for %s - %s\n",
762 command
, strerror(save_errno
));
766 if (WIFEXITED(status
)) {
767 int pstatus
= WEXITSTATUS(status
);
768 if (WIFSIGNALED(status
)) {
769 fprintf(stderr
, "%s terminated with signal %d\n",
770 command
, WTERMSIG(status
));
772 } else if (pstatus
>= 64 && pstatus
< 255) {
773 fprintf(stderr
, "%s failed with error %d\n",
774 command
, pstatus
-64);
780 } else if (WIFSIGNALED(status
)) {
781 fprintf(stderr
, "%s terminated with signal %d\n",
782 command
, WTERMSIG(status
));
789 static void leader_handler(uint64_t srvid
,
793 struct ctdb_context
*ctdb
= talloc_get_type_abort(
794 private_data
, struct ctdb_context
);
799 ret
= ctdb_uint32_pull(data
.dptr
, data
.dsize
, &leader_pnn
, &np
);
805 ctdb
->leader_pnn
= leader_pnn
;
808 static bool get_leader_done(void *private_data
)
810 struct ctdb_context
*ctdb
= talloc_get_type_abort(
811 private_data
, struct ctdb_context
);
813 return ctdb
->leader_pnn
!= CTDB_UNKNOWN_PNN
;
816 static int get_leader(TALLOC_CTX
*mem_ctx
,
817 struct ctdb_context
*ctdb
,
822 ret
= ctdb_client_wait_func_timeout(ctdb
->ev
,
827 * If ETIMEDOUT then assume there is no leader and succeed so
828 * initial value of CTDB_UNKNOWN_PNN is returned
830 if (ret
== ETIMEDOUT
) {
832 } else if (ret
!= 0) {
833 fprintf(stderr
, "Error getting leader\n");
837 *leader
= ctdb
->leader_pnn
;
845 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
846 int argc
, const char **argv
)
848 printf("%s\n", SAMBA_VERSION_STRING
);
852 static bool partially_online(TALLOC_CTX
*mem_ctx
,
853 struct ctdb_context
*ctdb
,
854 struct ctdb_node_and_flags
*node
)
856 struct ctdb_iface_list
*iface_list
;
861 if (node
->flags
!= 0) {
865 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
866 node
->pnn
, TIMEOUT(), &iface_list
);
872 for (i
=0; i
< iface_list
->num
; i
++) {
873 if (iface_list
->iface
[i
].link_state
== 0) {
882 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
883 struct ctdb_context
*ctdb
,
884 struct ctdb_node_map
*nodemap
,
887 struct ctdb_node_and_flags
*node
;
890 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
894 "Disconnected", options
.sep
,
895 "Unknown", options
.sep
,
896 "Banned", options
.sep
,
897 "Disabled", options
.sep
,
898 "Unhealthy", options
.sep
,
899 "Stopped", options
.sep
,
900 "Inactive", options
.sep
,
901 "PartiallyOnline", options
.sep
,
902 "ThisNode", options
.sep
);
904 for (i
=0; i
<nodemap
->num
; i
++) {
905 node
= &nodemap
->node
[i
];
906 if (node
->flags
& NODE_FLAGS_DELETED
) {
910 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
912 node
->pnn
, options
.sep
,
913 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
915 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
916 !! (node
->flags
& NODE_FLAGS_UNKNOWN
), options
.sep
,
917 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
918 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
920 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
921 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
922 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
923 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
924 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
929 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
930 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
933 struct ctdb_node_and_flags
*node
;
934 int num_deleted_nodes
= 0;
937 for (i
=0; i
<nodemap
->num
; i
++) {
938 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
944 if (num_deleted_nodes
== 0) {
945 printf("Number of nodes:%d\n", nodemap
->num
);
947 printf("Number of nodes:%d "
948 "(including %d deleted nodes)\n",
949 nodemap
->num
, num_deleted_nodes
);
953 for (i
=0; i
<nodemap
->num
; i
++) {
954 node
= &nodemap
->node
[i
];
955 if (node
->flags
& NODE_FLAGS_DELETED
) {
959 printf("pnn:%u %-16s %s%s\n",
961 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
962 partially_online(mem_ctx
, ctdb
, node
) ?
964 pretty_print_flags(mem_ctx
, node
->flags
),
965 node
->pnn
== mypnn
? " (THIS NODE)" : "");
969 static void print_status(TALLOC_CTX
*mem_ctx
,
970 struct ctdb_context
*ctdb
,
971 struct ctdb_node_map
*nodemap
,
973 struct ctdb_vnn_map
*vnnmap
,
979 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
981 if (vnnmap
->generation
== INVALID_GENERATION
) {
982 printf("Generation:INVALID\n");
984 printf("Generation:%u\n", vnnmap
->generation
);
986 printf("Size:%d\n", vnnmap
->size
);
987 for (i
=0; i
<vnnmap
->size
; i
++) {
988 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
991 printf("Recovery mode:%s (%d)\n",
992 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
998 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
999 int argc
, const char **argv
)
1001 struct ctdb_node_map
*nodemap_in
;
1002 struct ctdb_node_map
*nodemap
;
1003 struct ctdb_vnn_map
*vnnmap
;
1012 nodemap_in
= get_nodemap(ctdb
, false);
1013 if (nodemap_in
== NULL
) {
1017 nodemap
= get_nodemap_unknown(mem_ctx
, ctdb
, nodemap_in
);
1018 if (nodemap
== NULL
) {
1022 if (options
.machinereadable
== 1) {
1023 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
1027 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1028 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
1033 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1034 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
1039 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
1044 print_status(mem_ctx
,
1054 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1055 int argc
, const char **argv
)
1057 struct ctdb_uptime
*uptime
;
1058 int ret
, tmp
, days
, hours
, minutes
, seconds
;
1060 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1061 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
1066 printf("Current time of node %-4u : %s",
1067 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
1069 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
1070 seconds
= tmp
% 60; tmp
/= 60;
1071 minutes
= tmp
% 60; tmp
/= 60;
1072 hours
= tmp
% 24; tmp
/= 24;
1075 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
1076 days
, hours
, minutes
, seconds
,
1077 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
1079 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
1080 seconds
= tmp
% 60; tmp
/= 60;
1081 minutes
= tmp
% 60; tmp
/= 60;
1082 hours
= tmp
% 24; tmp
/= 24;
1085 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
1086 days
, hours
, minutes
, seconds
,
1087 ctime(&uptime
->last_recovery_finished
.tv_sec
));
1089 printf("Duration of last recovery/failover: %lf seconds\n",
1090 timeval_delta(&uptime
->last_recovery_finished
,
1091 &uptime
->last_recovery_started
));
1096 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1097 int argc
, const char **argv
)
1100 int ret
, num_clients
;
1102 tv
= timeval_current();
1103 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1104 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
1109 printf("response from %u time=%.6f sec (%d clients)\n",
1110 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
1114 const char *runstate_to_string(enum ctdb_runstate runstate
);
1115 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
1117 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1118 int argc
, const char **argv
)
1120 enum ctdb_runstate runstate
;
1124 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1125 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
1131 for (i
=0; i
<argc
; i
++) {
1132 enum ctdb_runstate t
;
1135 t
= ctdb_runstate_from_string(argv
[i
]);
1136 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
1137 printf("Invalid run state (%s)\n", argv
[i
]);
1141 if (t
== runstate
) {
1148 printf("CTDB not in required run state (got %s)\n",
1149 ctdb_runstate_to_string(runstate
));
1153 printf("%s\n", ctdb_runstate_to_string(runstate
));
1157 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1158 int argc
, const char **argv
)
1160 struct ctdb_var_list
*tun_var_list
;
1169 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1170 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1173 "Failed to get list of variables from node %u\n",
1179 for (i
=0; i
<tun_var_list
->count
; i
++) {
1180 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1187 printf("No such tunable %s\n", argv
[0]);
1191 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1192 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1197 printf("%-26s = %u\n", argv
[0], value
);
1201 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1202 int argc
, const char **argv
)
1204 struct ctdb_var_list
*tun_var_list
;
1205 struct ctdb_tunable tunable
;
1214 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1215 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1218 "Failed to get list of variables from node %u\n",
1224 for (i
=0; i
<tun_var_list
->count
; i
++) {
1225 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1232 printf("No such tunable %s\n", argv
[0]);
1236 tunable
.name
= argv
[0];
1237 tunable
.value
= smb_strtoul(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1242 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1243 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1247 "Setting obsolete tunable variable '%s'\n",
1256 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1257 int argc
, const char **argv
)
1259 struct ctdb_var_list
*tun_var_list
;
1266 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1267 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1272 for (i
=0; i
<tun_var_list
->count
; i
++) {
1273 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1282 } stats_fields
[] = {
1283 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1284 STATISTICS_FIELD(num_clients
),
1285 STATISTICS_FIELD(frozen
),
1286 STATISTICS_FIELD(recovering
),
1287 STATISTICS_FIELD(num_recoveries
),
1288 STATISTICS_FIELD(client_packets_sent
),
1289 STATISTICS_FIELD(client_packets_recv
),
1290 STATISTICS_FIELD(node_packets_sent
),
1291 STATISTICS_FIELD(node_packets_recv
),
1292 STATISTICS_FIELD(keepalive_packets_sent
),
1293 STATISTICS_FIELD(keepalive_packets_recv
),
1294 STATISTICS_FIELD(node
.req_call
),
1295 STATISTICS_FIELD(node
.reply_call
),
1296 STATISTICS_FIELD(node
.req_dmaster
),
1297 STATISTICS_FIELD(node
.reply_dmaster
),
1298 STATISTICS_FIELD(node
.reply_error
),
1299 STATISTICS_FIELD(node
.req_message
),
1300 STATISTICS_FIELD(node
.req_control
),
1301 STATISTICS_FIELD(node
.reply_control
),
1302 STATISTICS_FIELD(node
.req_tunnel
),
1303 STATISTICS_FIELD(client
.req_call
),
1304 STATISTICS_FIELD(client
.req_message
),
1305 STATISTICS_FIELD(client
.req_control
),
1306 STATISTICS_FIELD(client
.req_tunnel
),
1307 STATISTICS_FIELD(timeouts
.call
),
1308 STATISTICS_FIELD(timeouts
.control
),
1309 STATISTICS_FIELD(timeouts
.traverse
),
1310 STATISTICS_FIELD(locks
.num_calls
),
1311 STATISTICS_FIELD(locks
.num_current
),
1312 STATISTICS_FIELD(locks
.num_pending
),
1313 STATISTICS_FIELD(locks
.num_failed
),
1314 STATISTICS_FIELD(total_calls
),
1315 STATISTICS_FIELD(pending_calls
),
1316 STATISTICS_FIELD(childwrite_calls
),
1317 STATISTICS_FIELD(pending_childwrite_calls
),
1318 STATISTICS_FIELD(memory_used
),
1319 STATISTICS_FIELD(max_hop_count
),
1320 STATISTICS_FIELD(total_ro_delegations
),
1321 STATISTICS_FIELD(total_ro_revokes
),
1324 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1326 static void print_statistics_machine(struct ctdb_statistics
*s
,
1332 printf("CTDB version%s", options
.sep
);
1333 printf("Current time of statistics%s", options
.sep
);
1334 printf("Statistics collected since%s", options
.sep
);
1335 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1336 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1338 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1339 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1340 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1341 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1343 printf("num_reclock_recd_latency%s", options
.sep
);
1344 printf("min_reclock_recd_latency%s", options
.sep
);
1345 printf("avg_reclock_recd_latency%s", options
.sep
);
1346 printf("max_reclock_recd_latency%s", options
.sep
);
1348 printf("num_call_latency%s", options
.sep
);
1349 printf("min_call_latency%s", options
.sep
);
1350 printf("avg_call_latency%s", options
.sep
);
1351 printf("max_call_latency%s", options
.sep
);
1353 printf("num_lockwait_latency%s", options
.sep
);
1354 printf("min_lockwait_latency%s", options
.sep
);
1355 printf("avg_lockwait_latency%s", options
.sep
);
1356 printf("max_lockwait_latency%s", options
.sep
);
1358 printf("num_childwrite_latency%s", options
.sep
);
1359 printf("min_childwrite_latency%s", options
.sep
);
1360 printf("avg_childwrite_latency%s", options
.sep
);
1361 printf("max_childwrite_latency%s", options
.sep
);
1365 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1366 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1367 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1368 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1370 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1373 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1374 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1375 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1376 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1378 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1379 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1380 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1381 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1383 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1384 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1385 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1386 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1388 printf("%u%s", s
->locks
.latency
.num
, options
.sep
);
1389 printf("%.6f%s", s
->locks
.latency
.min
, options
.sep
);
1390 printf("%.6f%s", LATENCY_AVG(s
->locks
.latency
), options
.sep
);
1391 printf("%.6f%s", s
->locks
.latency
.max
, options
.sep
);
1393 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1394 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1395 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1396 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1400 static void print_statistics(struct ctdb_statistics
*s
)
1402 int tmp
, days
, hours
, minutes
, seconds
;
1404 const char *prefix
= NULL
;
1407 tmp
= s
->statistics_current_time
.tv_sec
-
1408 s
->statistics_start_time
.tv_sec
;
1409 seconds
= tmp
% 60; tmp
/= 60;
1410 minutes
= tmp
% 60; tmp
/= 60;
1411 hours
= tmp
% 24; tmp
/= 24;
1414 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1415 printf("Current time of statistics : %s",
1416 ctime(&s
->statistics_current_time
.tv_sec
));
1417 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1418 days
, hours
, minutes
, seconds
,
1419 ctime(&s
->statistics_start_time
.tv_sec
));
1421 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1422 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1423 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1425 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1426 prefix
= stats_fields
[i
].name
;
1427 printf(" %*.*s\n", preflen
-1, preflen
-1,
1428 stats_fields
[i
].name
);
1433 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1434 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1435 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1438 printf(" hop_count_buckets:");
1439 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1440 printf(" %d", s
->hop_count_bucket
[i
]);
1443 printf(" lock_buckets:");
1444 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1445 printf(" %d", s
->locks
.buckets
[i
]);
1448 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1449 "locks_latency MIN/AVG/MAX",
1450 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1451 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1453 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1454 "reclock_ctdbd MIN/AVG/MAX",
1455 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1456 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1458 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1459 "reclock_recd MIN/AVG/MAX",
1460 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1461 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1463 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1464 "call_latency MIN/AVG/MAX",
1465 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1466 s
->call_latency
.max
, s
->call_latency
.num
);
1468 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1469 "childwrite_latency MIN/AVG/MAX",
1470 s
->childwrite_latency
.min
,
1471 LATENCY_AVG(s
->childwrite_latency
),
1472 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1475 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1476 int argc
, const char **argv
)
1478 struct ctdb_statistics
*stats
;
1482 usage("statistics");
1485 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1486 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1491 if (options
.machinereadable
) {
1492 print_statistics_machine(stats
, true);
1494 print_statistics(stats
);
1500 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1501 struct ctdb_context
*ctdb
,
1502 int argc
, const char **argv
)
1507 usage("statisticsreset");
1510 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1511 ctdb
->cmd_pnn
, TIMEOUT());
1519 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1520 int argc
, const char **argv
)
1522 struct ctdb_statistics_list
*slist
;
1523 int ret
, count
= 0, i
;
1524 bool show_header
= true;
1531 count
= atoi(argv
[0]);
1534 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1535 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1540 for (i
=0; i
<slist
->num
; i
++) {
1541 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1544 if (options
.machinereadable
== 1) {
1545 print_statistics_machine(&slist
->stats
[i
],
1547 show_header
= false;
1549 print_statistics(&slist
->stats
[i
]);
1551 if (count
> 0 && i
== count
) {
1559 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1561 const struct ctdb_public_ip
*ip_a
= a
;
1562 const struct ctdb_public_ip
*ip_b
= b
;
1564 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1567 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1568 struct ctdb_public_ip_list
*ips
,
1569 struct ctdb_public_ip_info
**ipinfo
,
1573 char *conf
, *avail
, *active
;
1575 if (options
.machinereadable
== 1) {
1576 printf("%s%s%s%s%s", options
.sep
,
1577 "Public IP", options
.sep
,
1578 "Node", options
.sep
);
1579 if (options
.verbose
== 1) {
1580 printf("%s%s%s%s%s%s\n",
1581 "ActiveInterfaces", options
.sep
,
1582 "AvailableInterfaces", options
.sep
,
1583 "ConfiguredInterfaces", options
.sep
);
1589 printf("Public IPs on ALL nodes\n");
1591 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1595 for (i
= 0; i
< ips
->num
; i
++) {
1597 if (options
.machinereadable
== 1) {
1598 printf("%s%s%s%d%s", options
.sep
,
1599 ctdb_sock_addr_to_string(
1600 mem_ctx
, &ips
->ip
[i
].addr
, false),
1602 (int)ips
->ip
[i
].pnn
, options
.sep
);
1604 printf("%s", ctdb_sock_addr_to_string(
1605 mem_ctx
, &ips
->ip
[i
].addr
, false));
1608 if (options
.verbose
== 0) {
1609 if (options
.machinereadable
== 1) {
1612 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1621 if (ipinfo
[i
] == NULL
) {
1625 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1626 struct ctdb_iface
*iface
;
1628 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1630 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1632 conf
= talloc_asprintf_append(
1633 conf
, ",%s", iface
->name
);
1636 if (ipinfo
[i
]->active_idx
== j
) {
1637 active
= iface
->name
;
1640 if (iface
->link_state
== 0) {
1644 if (avail
== NULL
) {
1645 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1647 avail
= talloc_asprintf_append(
1648 avail
, ",%s", iface
->name
);
1654 if (options
.machinereadable
== 1) {
1655 printf("%s%s%s%s%s%s\n",
1656 active
? active
: "", options
.sep
,
1657 avail
? avail
: "", options
.sep
,
1658 conf
? conf
: "", options
.sep
);
1660 printf(" node[%d] active[%s] available[%s]"
1661 " configured[%s]\n",
1662 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1663 avail
? avail
: "", conf
? conf
: "");
1668 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1669 size_t datalen
, void *private_data
)
1671 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1672 private_data
, struct ctdb_public_ip_list
);
1673 struct ctdb_public_ip
*ip
;
1675 ip
= (struct ctdb_public_ip
*)databuf
;
1676 ips
->ip
[ips
->num
] = *ip
;
1682 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1683 struct ctdb_public_ip_list
**out
)
1685 struct ctdb_node_map
*nodemap
;
1686 struct ctdb_public_ip_list
*ips
;
1687 struct db_hash_context
*ipdb
;
1692 nodemap
= get_nodemap(ctdb
, false);
1693 if (nodemap
== NULL
) {
1697 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1702 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1708 for (i
=0; i
<count
; i
++) {
1709 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1710 pnn_list
[i
], TIMEOUT(),
1716 for (j
=0; j
<ips
->num
; j
++) {
1717 struct ctdb_public_ip ip
;
1719 ip
.pnn
= ips
->ip
[j
].pnn
;
1720 ip
.addr
= ips
->ip
[j
].addr
;
1722 if (pnn_list
[i
] == ip
.pnn
) {
1723 /* Node claims IP is hosted on it, so
1724 * save that information
1726 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1728 (uint8_t *)&ip
, sizeof(ip
));
1733 /* Node thinks IP is hosted elsewhere,
1734 * so overwrite with CTDB_UNKNOWN_PNN
1735 * if there's no existing entry
1737 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1739 if (ret
== ENOENT
) {
1740 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1741 ret
= db_hash_add(ipdb
,
1742 (uint8_t *)&ip
.addr
,
1756 talloc_free(pnn_list
);
1758 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1763 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1768 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1769 if (ips
->ip
== NULL
) {
1773 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1778 if ((unsigned int)count
!= ips
->num
) {
1792 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1793 int argc
, const char **argv
)
1795 struct ctdb_public_ip_list
*ips
;
1796 struct ctdb_public_ip_info
**ipinfo
;
1799 bool do_all
= false;
1806 if (strcmp(argv
[0], "all") == 0) {
1814 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1816 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1817 ctdb
->cmd_pnn
, TIMEOUT(),
1824 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1825 ctdb_public_ip_cmp
);
1827 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1828 if (ipinfo
== NULL
) {
1832 for (i
=0; i
<ips
->num
; i
++) {
1835 pnn
= ips
->ip
[i
].pnn
;
1837 pnn
= ctdb
->cmd_pnn
;
1839 if (pnn
== CTDB_UNKNOWN_PNN
) {
1843 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1845 TIMEOUT(), &ips
->ip
[i
].addr
,
1852 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1856 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1857 int argc
, const char **argv
)
1859 struct ctdb_public_ip_info
*ipinfo
;
1860 ctdb_sock_addr addr
;
1868 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1870 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1874 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1875 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1879 printf("Node %u does not know about IP %s\n",
1880 ctdb
->cmd_pnn
, argv
[0]);
1885 printf("Public IP[%s] info on node %u\n",
1886 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1889 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1890 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1891 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1893 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1894 struct ctdb_iface
*iface
;
1896 iface
= &ipinfo
->ifaces
->iface
[i
];
1897 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1898 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1900 iface
->link_state
== 0 ? "down" : "up",
1902 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1908 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1909 int argc
, const char **argv
)
1911 struct ctdb_iface_list
*ifaces
;
1919 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1920 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1925 if (ifaces
->num
== 0) {
1926 printf("No interfaces configured on node %u\n",
1931 if (options
.machinereadable
) {
1932 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1933 "Name", options
.sep
,
1934 "LinkStatus", options
.sep
,
1935 "References", options
.sep
);
1937 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1940 for (i
=0; i
<ifaces
->num
; i
++) {
1941 if (options
.machinereadable
) {
1942 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1943 ifaces
->iface
[i
].name
, options
.sep
,
1944 ifaces
->iface
[i
].link_state
, options
.sep
,
1945 ifaces
->iface
[i
].references
, options
.sep
);
1947 printf("name:%s link:%s references:%u\n",
1948 ifaces
->iface
[i
].name
,
1949 ifaces
->iface
[i
].link_state
? "up" : "down",
1950 ifaces
->iface
[i
].references
);
1957 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1958 int argc
, const char **argv
)
1960 struct ctdb_iface_list
*ifaces
;
1961 struct ctdb_iface
*iface
;
1966 usage("setifacelink");
1969 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1970 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1974 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1975 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1978 "Failed to get interface information from node %u\n",
1984 for (i
=0; i
<ifaces
->num
; i
++) {
1985 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1986 iface
= &ifaces
->iface
[i
];
1991 if (iface
== NULL
) {
1992 printf("Interface %s not configured on node %u\n",
1993 argv
[0], ctdb
->cmd_pnn
);
1997 if (strcmp(argv
[1], "up") == 0) {
1998 iface
->link_state
= 1;
1999 } else if (strcmp(argv
[1], "down") == 0) {
2000 iface
->link_state
= 0;
2002 usage("setifacelink");
2006 iface
->references
= 0;
2008 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2009 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
2017 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
2018 struct ctdb_context
*ctdb
,
2019 int argc
, const char **argv
)
2026 if (argc
!= 1 && argc
!= 2) {
2027 usage("process-exists");
2030 pid
= atoi(argv
[0]);
2032 srvid
= smb_strtoull(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2039 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2040 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
2042 struct ctdb_pid_srvid pid_srvid
;
2044 pid_srvid
.pid
= pid
;
2045 pid_srvid
.srvid
= srvid
;
2047 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
2048 ctdb
->client
, ctdb
->cmd_pnn
,
2049 TIMEOUT(), &pid_srvid
,
2058 printf("PID %d %s\n", pid
,
2059 (status
== 0 ? "exists" : "does not exist"));
2061 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
2062 (status
== 0 ? "exists" : "does not exist"));
2067 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2068 int argc
, const char **argv
)
2070 struct ctdb_dbid_map
*dbmap
;
2078 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2079 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
2084 if (options
.machinereadable
== 1) {
2085 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
2088 "Name", options
.sep
,
2089 "Path", options
.sep
,
2090 "Persistent", options
.sep
,
2091 "Sticky", options
.sep
,
2092 "Unhealthy", options
.sep
,
2093 "Readonly", options
.sep
,
2094 "Replicated", options
.sep
);
2096 printf("Number of databases:%d\n", dbmap
->num
);
2099 for (i
=0; i
<dbmap
->num
; i
++) {
2109 db_id
= dbmap
->dbs
[i
].db_id
;
2111 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2112 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2118 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2119 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2125 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2126 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2132 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
2133 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
2134 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
2135 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
2137 if (options
.machinereadable
== 1) {
2138 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2143 !! (persistent
), options
.sep
,
2144 !! (sticky
), options
.sep
,
2145 !! (health
), options
.sep
,
2146 !! (readonly
), options
.sep
,
2147 !! (replicated
), options
.sep
);
2149 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2151 persistent
? " PERSISTENT" : "",
2152 sticky
? " STICKY" : "",
2153 readonly
? " READONLY" : "",
2154 replicated
? " REPLICATED" : "",
2155 health
? " UNHEALTHY" : "");
2158 talloc_free(discard_const(name
));
2159 talloc_free(discard_const(path
));
2160 talloc_free(discard_const(health
));
2166 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2167 int argc
, const char **argv
)
2170 const char *db_name
, *db_path
, *db_health
;
2175 usage("getdbstatus");
2178 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2182 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2183 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2189 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2190 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2196 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2197 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2198 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2199 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2200 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2201 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2202 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2206 struct dump_record_state
{
2210 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2212 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2216 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2217 for (i
=0; i
<val
.dsize
; i
++) {
2218 if (ISASCII(val
.dptr
[i
])) {
2219 fprintf(stdout
, "%c", val
.dptr
[i
]);
2221 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2224 fprintf(stdout
, "\"\n");
2227 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2229 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2230 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2231 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2232 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2233 fprintf(stdout
, " MIGRATED_WITH_DATA");
2235 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2236 fprintf(stdout
, " VACUUM_MIGRATED");
2238 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2239 fprintf(stdout
, " AUTOMATIC");
2241 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2242 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2244 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2245 fprintf(stdout
, " RO_HAVE_READONLY");
2247 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2248 fprintf(stdout
, " RO_REVOKING_READONLY");
2250 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2251 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2253 fprintf(stdout
, "\n");
2257 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2258 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2260 struct dump_record_state
*state
=
2261 (struct dump_record_state
*)private_data
;
2265 dump_tdb_data("key", key
);
2266 dump_ltdb_header(header
);
2267 dump_tdb_data("data", data
);
2268 fprintf(stdout
, "\n");
2273 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2274 int argc
, const char **argv
)
2276 struct ctdb_db_context
*db
;
2277 const char *db_name
;
2280 struct dump_record_state state
;
2287 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2291 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2294 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2300 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2301 ctdb
->cmd_pnn
, TIMEOUT(),
2302 dump_record
, &state
);
2304 printf("Dumped %u records\n", state
.count
);
2309 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2310 int argc
, const char **argv
)
2312 struct ctdb_db_context
*db
;
2313 const char *db_name
;
2316 struct dump_record_state state
;
2323 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2327 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2330 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2335 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2337 printf("Dumped %u record(s)\n", state
.count
);
2342 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2343 struct ctdb_context
*ctdb
,
2344 int argc
, const char **argv
)
2350 usage("getcapabilities");
2353 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2354 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2359 if (options
.machinereadable
== 1) {
2360 printf("%s%s%s%s%s\n",
2362 "LEADER", options
.sep
,
2363 "LMASTER", options
.sep
);
2364 printf("%s%d%s%d%s\n", options
.sep
,
2365 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2366 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2368 printf("LEADER: %s\n",
2369 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2370 printf("LMASTER: %s\n",
2371 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2377 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2378 int argc
, const char **argv
)
2380 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2384 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2385 int argc
, const char **argv
)
2387 char *t
, *lvs_helper
= NULL
;
2393 t
= getenv("CTDB_LVS_HELPER");
2395 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2397 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2398 CTDB_HELPER_BINDIR
);
2401 if (lvs_helper
== NULL
) {
2402 fprintf(stderr
, "Unable to set LVS helper\n");
2406 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2409 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2410 int argc
, const char **argv
)
2420 found
= debug_level_parse(argv
[0], &log_level
);
2423 "Invalid debug level '%s'. Valid levels are:\n",
2425 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2429 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2430 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2438 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2439 int argc
, const char **argv
)
2442 const char *log_str
;
2449 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2450 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2455 log_str
= debug_level_to_string(loglevel
);
2456 printf("%s\n", log_str
);
2461 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2462 int argc
, const char **argv
)
2464 const char *db_name
;
2465 uint8_t db_flags
= 0;
2468 if (argc
< 1 || argc
> 2) {
2474 if (strcmp(argv
[1], "persistent") == 0) {
2475 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2476 } else if (strcmp(argv
[1], "readonly") == 0) {
2477 db_flags
= CTDB_DB_FLAGS_READONLY
;
2478 } else if (strcmp(argv
[1], "sticky") == 0) {
2479 db_flags
= CTDB_DB_FLAGS_STICKY
;
2480 } else if (strcmp(argv
[1], "replicated") == 0) {
2481 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2487 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2496 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2497 int argc
, const char **argv
)
2499 const char *db_name
;
2502 struct ctdb_node_map
*nodemap
;
2511 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2512 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2517 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2518 fprintf(stderr
, "Database cannot be detached"
2519 " when recovery is active\n");
2523 nodemap
= get_nodemap(ctdb
, false);
2524 if (nodemap
== NULL
) {
2528 for (j
=0; j
<nodemap
->num
; j
++) {
2531 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DISCONNECTED
) {
2534 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DELETED
) {
2537 if (nodemap
->node
[j
].flags
& NODE_FLAGS_INACTIVE
) {
2538 fprintf(stderr
, "Database cannot be detached on"
2539 " inactive (stopped or banned) node %u\n",
2540 nodemap
->node
[j
].pnn
);
2544 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2545 nodemap
->node
[j
].pnn
, TIMEOUT(),
2546 "AllowClientDBAttach", &value
);
2549 "Unable to get tunable AllowClientDBAttach"
2550 " from node %u\n", nodemap
->node
[j
].pnn
);
2556 "Database access is still active on node %u."
2557 " Set AllowclientDBAttach=0 on all nodes.\n",
2558 nodemap
->node
[j
].pnn
);
2564 for (i
=0; i
<argc
; i
++) {
2565 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2571 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2573 "Only volatile databases can be detached\n");
2577 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2579 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2587 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2588 int argc
, const char **argv
)
2590 const char *mem_str
;
2594 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2595 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2600 n
= write(1, mem_str
, strlen(mem_str
));
2601 if (n
< 0 || (size_t)n
!= strlen(mem_str
)) {
2602 fprintf(stderr
, "Failed to write talloc summary\n");
2609 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2611 bool *done
= (bool *)private_data
;
2615 len
= strnlen((const char *)data
.dptr
, data
.dsize
);
2616 n
= write(1, data
.dptr
, len
);
2617 if (n
< 0 || (size_t)n
!= len
) {
2618 fprintf(stderr
, "Failed to write talloc summary\n");
2624 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2625 int argc
, const char **argv
)
2627 struct ctdb_srvid_message msg
= { 0 };
2631 msg
.pnn
= ctdb
->pnn
;
2632 msg
.srvid
= next_srvid(ctdb
);
2634 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2635 msg
.srvid
, dump_memory
, &done
);
2640 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2641 ctdb
->cmd_pnn
, &msg
);
2646 ctdb_client_wait(ctdb
->ev
, &done
);
2650 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2651 int argc
, const char **argv
)
2656 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2657 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2662 printf("%u\n", pid
);
2666 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2667 const char *desc
, uint32_t flag
, bool set_flag
)
2669 struct ctdb_node_map
*nodemap
;
2672 nodemap
= get_nodemap(ctdb
, false);
2673 if (nodemap
== NULL
) {
2677 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2678 if (set_flag
== flag_is_set
) {
2680 fprintf(stderr
, "Node %u is already %s\n",
2681 ctdb
->cmd_pnn
, desc
);
2683 fprintf(stderr
, "Node %u is not %s\n",
2684 ctdb
->cmd_pnn
, desc
);
2692 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2693 uint32_t flag
, bool set_flag
)
2695 struct ctdb_node_map
*nodemap
;
2699 nodemap
= get_nodemap(ctdb
, true);
2700 if (nodemap
== NULL
) {
2702 "Failed to get nodemap, trying again\n");
2707 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2708 if (flag_is_set
== set_flag
) {
2716 struct ipreallocate_state
{
2721 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2724 struct ipreallocate_state
*state
=
2725 (struct ipreallocate_state
*)private_data
;
2727 if (data
.dsize
!= sizeof(int)) {
2732 state
->status
= *(int *)data
.dptr
;
2736 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2738 struct ctdb_srvid_message msg
= { 0 };
2739 struct ipreallocate_state state
;
2742 msg
.pnn
= ctdb
->pnn
;
2743 msg
.srvid
= next_srvid(ctdb
);
2746 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2748 ipreallocate_handler
, &state
);
2754 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2756 CTDB_BROADCAST_CONNECTED
,
2762 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2768 if (state
.status
>= 0) {
2777 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2782 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2783 int argc
, const char **argv
)
2791 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2792 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2797 ret
= ctdb_ctrl_disable_node(mem_ctx
,
2803 fprintf(stderr
, "Failed to disable node %u\n", ctdb
->cmd_pnn
);
2807 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2808 return ipreallocate(mem_ctx
, ctdb
);
2811 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2812 int argc
, const char **argv
)
2820 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2821 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2826 ret
= ctdb_ctrl_enable_node(mem_ctx
,
2832 fprintf(stderr
, "Failed to enable node %u\n", ctdb
->cmd_pnn
);
2836 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2837 return ipreallocate(mem_ctx
, ctdb
);
2840 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2841 int argc
, const char **argv
)
2849 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2850 NODE_FLAGS_STOPPED
, true);
2855 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2856 ctdb
->cmd_pnn
, TIMEOUT());
2858 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2862 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2863 return ipreallocate(mem_ctx
, ctdb
);
2866 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2867 int argc
, const char **argv
)
2875 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2876 NODE_FLAGS_STOPPED
, false);
2881 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2882 ctdb
->cmd_pnn
, TIMEOUT());
2884 fprintf(stderr
, "Failed to continue stopped node %u\n",
2889 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2890 return ipreallocate(mem_ctx
, ctdb
);
2893 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2894 int argc
, const char **argv
)
2896 struct ctdb_ban_state ban_state
;
2903 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2904 NODE_FLAGS_BANNED
, true);
2909 ban_state
.pnn
= ctdb
->cmd_pnn
;
2910 ban_state
.time
= smb_strtoul(argv
[0], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2915 if (ban_state
.time
== 0) {
2916 fprintf(stderr
, "Ban time cannot be zero\n");
2920 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2921 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2923 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2927 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2928 return ipreallocate(mem_ctx
, ctdb
);
2932 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2933 int argc
, const char **argv
)
2935 struct ctdb_ban_state ban_state
;
2942 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2943 NODE_FLAGS_BANNED
, false);
2948 ban_state
.pnn
= ctdb
->cmd_pnn
;
2951 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2952 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2954 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2958 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2959 return ipreallocate(mem_ctx
, ctdb
);
2963 static void wait_for_shutdown(void *private_data
)
2965 bool *done
= (bool *)private_data
;
2970 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2971 int argc
, const char **argv
)
2980 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2981 ctdb_client_set_disconnect_callback(ctdb
->client
,
2986 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2987 ctdb
->cmd_pnn
, TIMEOUT());
2989 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2993 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2994 ctdb_client_wait(ctdb
->ev
, &done
);
3000 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3001 uint32_t *generation
)
3005 struct ctdb_vnn_map
*vnnmap
;
3009 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
3011 fprintf(stderr
, "Failed to find leader\n");
3015 ret
= ctdb_ctrl_get_recmode(mem_ctx
,
3023 "Failed to get recovery mode from node %u\n",
3028 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
3033 ret
= ctdb_ctrl_getvnnmap(mem_ctx
,
3041 "Failed to get generation from node %u\n",
3046 if (vnnmap
->generation
== INVALID_GENERATION
) {
3047 talloc_free(vnnmap
);
3052 *generation
= vnnmap
->generation
;
3053 talloc_free(vnnmap
);
3058 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3059 int argc
, const char **argv
)
3061 uint32_t generation
, next_generation
;
3068 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
3073 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3074 ctdb
->cmd_pnn
, TIMEOUT(),
3075 CTDB_RECOVERY_ACTIVE
);
3077 fprintf(stderr
, "Failed to set recovery mode active\n");
3082 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
3085 "Failed to confirm end of recovery\n");
3089 if (next_generation
!= generation
) {
3099 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3100 int argc
, const char **argv
)
3103 usage("ipreallocate");
3106 return ipreallocate(mem_ctx
, ctdb
);
3109 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3110 int argc
, const char **argv
)
3112 struct ctdb_addr_info addr_info
;
3119 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
3121 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3124 addr_info
.iface
= argv
[1];
3126 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3127 ctdb
->cmd_pnn
, TIMEOUT(),
3130 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3138 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3139 int argc
, const char **argv
)
3141 ctdb_sock_addr src
, dst
;
3144 if (argc
!= 0 && argc
!= 2) {
3149 struct ctdb_connection_list
*clist
;
3151 unsigned int num_failed
;
3153 /* Client first but the src/dst logic is confused */
3154 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3160 for (i
= 0; i
< clist
->num
; i
++) {
3161 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3162 &clist
->conn
[i
].dst
,
3171 if (num_failed
> 0) {
3172 fprintf(stderr
, "Failed to send %d tickles\n",
3181 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3183 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3187 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3189 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3193 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3195 fprintf(stderr
, "Failed to send tickle ack\n");
3202 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3203 int argc
, const char **argv
)
3205 ctdb_sock_addr addr
;
3206 struct ctdb_tickle_list
*tickles
;
3211 if (argc
< 1 || argc
> 2) {
3212 usage("gettickles");
3216 port
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3222 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3224 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3227 ctdb_sock_addr_set_port(&addr
, port
);
3229 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3230 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3233 fprintf(stderr
, "Failed to get list of connections\n");
3237 if (options
.machinereadable
) {
3238 printf("%s%s%s%s%s%s%s%s%s\n",
3240 "Source IP", options
.sep
,
3241 "Port", options
.sep
,
3242 "Destination IP", options
.sep
,
3243 "Port", options
.sep
);
3244 for (i
=0; i
<tickles
->num
; i
++) {
3245 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3246 ctdb_sock_addr_to_string(
3247 mem_ctx
, &tickles
->conn
[i
].src
, false),
3249 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3251 ctdb_sock_addr_to_string(
3252 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3254 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3258 printf("Connections for IP: %s\n",
3259 ctdb_sock_addr_to_string(mem_ctx
,
3260 &tickles
->addr
, false));
3261 printf("Num connections: %u\n", tickles
->num
);
3262 for (i
=0; i
<tickles
->num
; i
++) {
3263 printf("SRC: %s DST: %s\n",
3264 ctdb_sock_addr_to_string(
3265 mem_ctx
, &tickles
->conn
[i
].src
, true),
3266 ctdb_sock_addr_to_string(
3267 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3271 talloc_free(tickles
);
3275 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3276 struct ctdb_connection
*conn
);
3278 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3280 struct process_clist_state
{
3281 struct ctdb_connection_list
*clist
;
3283 unsigned int num_failed
, num_total
;
3284 clist_reply_func reply_func
;
3287 static void process_clist_done(struct tevent_req
*subreq
);
3289 static struct tevent_req
*process_clist_send(
3290 TALLOC_CTX
*mem_ctx
,
3291 struct ctdb_context
*ctdb
,
3292 struct ctdb_connection_list
*clist
,
3293 clist_request_func request_func
,
3294 clist_reply_func reply_func
)
3296 struct tevent_req
*req
, *subreq
;
3297 struct process_clist_state
*state
;
3298 struct ctdb_req_control request
;
3301 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3306 state
->clist
= clist
;
3307 state
->reply_func
= reply_func
;
3309 for (i
= 0; i
< clist
->num
; i
++) {
3310 request_func(&request
, &clist
->conn
[i
]);
3311 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3312 ctdb
->client
, ctdb
->cmd_pnn
,
3313 TIMEOUT(), &request
);
3314 if (tevent_req_nomem(subreq
, req
)) {
3315 return tevent_req_post(req
, ctdb
->ev
);
3317 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3323 static void process_clist_done(struct tevent_req
*subreq
)
3325 struct tevent_req
*req
= tevent_req_callback_data(
3326 subreq
, struct tevent_req
);
3327 struct process_clist_state
*state
= tevent_req_data(
3328 req
, struct process_clist_state
);
3329 struct ctdb_reply_control
*reply
;
3333 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3334 TALLOC_FREE(subreq
);
3336 state
->num_failed
+= 1;
3340 ret
= state
->reply_func(reply
);
3342 state
->num_failed
+= 1;
3347 state
->num_total
+= 1;
3348 if (state
->num_total
== state
->clist
->num
) {
3349 tevent_req_done(req
);
3353 static int process_clist_recv(struct tevent_req
*req
)
3355 struct process_clist_state
*state
= tevent_req_data(
3356 req
, struct process_clist_state
);
3358 return state
->num_failed
;
3361 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3362 int argc
, const char **argv
)
3364 struct ctdb_connection conn
;
3367 if (argc
!= 0 && argc
!= 2) {
3372 struct ctdb_connection_list
*clist
;
3373 struct tevent_req
*req
;
3375 /* Client first but the src/dst logic is confused */
3376 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3380 if (clist
->num
== 0) {
3384 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3385 ctdb_req_control_tcp_add_delayed_update
,
3386 ctdb_reply_control_tcp_add_delayed_update
);
3392 tevent_req_poll(req
, ctdb
->ev
);
3395 ret
= process_clist_recv(req
);
3397 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3404 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3406 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3409 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3411 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3415 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3416 ctdb
->client
, ctdb
->cmd_pnn
,
3419 fprintf(stderr
, "Failed to register connection\n");
3426 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3427 int argc
, const char **argv
)
3429 struct ctdb_connection conn
;
3432 if (argc
!= 0 && argc
!= 2) {
3437 struct ctdb_connection_list
*clist
;
3438 struct tevent_req
*req
;
3440 /* Client first but the src/dst logic is confused */
3441 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3445 if (clist
->num
== 0) {
3449 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3450 ctdb_req_control_tcp_remove
,
3451 ctdb_reply_control_tcp_remove
);
3457 tevent_req_poll(req
, ctdb
->ev
);
3460 ret
= process_clist_recv(req
);
3462 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3469 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3471 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3474 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3476 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3480 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3481 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3483 fprintf(stderr
, "Failed to unregister connection\n");
3490 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3491 int argc
, const char **argv
)
3493 struct ctdb_node_map
*nodemap
;
3500 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3501 if (nodemap
== NULL
) {
3505 for (i
=0; i
<nodemap
->num
; i
++) {
3506 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3510 if (options
.machinereadable
) {
3511 printf("%s%u%s%s%s\n", options
.sep
,
3512 nodemap
->node
[i
].pnn
, options
.sep
,
3513 ctdb_sock_addr_to_string(
3514 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3518 ctdb_sock_addr_to_string(
3519 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3526 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3527 struct ctdb_node_map
*nodemap2
)
3531 if (nodemap1
->num
!= nodemap2
->num
) {
3535 for (i
=0; i
<nodemap1
->num
; i
++) {
3536 struct ctdb_node_and_flags
*n1
, *n2
;
3538 n1
= &nodemap1
->node
[i
];
3539 n2
= &nodemap2
->node
[i
];
3541 if ((n1
->pnn
!= n2
->pnn
) ||
3542 (n1
->flags
!= n2
->flags
) ||
3543 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3551 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3552 struct ctdb_node_map
*nm
,
3553 struct ctdb_node_map
*fnm
,
3557 bool check_failed
= false;
3561 for (i
=0; i
<nm
->num
; i
++) {
3562 if (i
>= fnm
->num
) {
3564 "Node %u (%s) missing from nodes file\n",
3566 ctdb_sock_addr_to_string(
3567 mem_ctx
, &nm
->node
[i
].addr
, false));
3568 check_failed
= true;
3571 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3572 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3573 /* Node remains deleted */
3577 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3578 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3579 /* Node not newly nor previously deleted */
3580 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3581 &fnm
->node
[i
].addr
)) {
3583 "Node %u has changed IP address"
3584 " (was %s, now %s)\n",
3586 ctdb_sock_addr_to_string(
3588 &nm
->node
[i
].addr
, false),
3589 ctdb_sock_addr_to_string(
3591 &fnm
->node
[i
].addr
, false));
3592 check_failed
= true;
3594 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3596 "WARNING: Node %u is disconnected."
3597 " You MUST fix this node manually!\n",
3604 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3605 /* Node is being deleted */
3606 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3608 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3610 "ERROR: Node %u is still connected\n",
3612 check_failed
= true;
3617 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3618 /* Node was previously deleted */
3619 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3626 "ERROR: Nodes will not be reloaded due to previous error\n");
3630 /* Leftover nodes in file are NEW */
3631 for (; i
< fnm
->num
; i
++) {
3632 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3639 struct disable_recoveries_state
{
3641 unsigned int node_count
;
3647 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3650 struct disable_recoveries_state
*state
=
3651 (struct disable_recoveries_state
*)private_data
;
3655 if (data
.dsize
!= sizeof(int)) {
3660 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3661 ret
= *(int *)data
.dptr
;
3663 state
->status
= ret
;
3667 for (i
=0; i
<state
->node_count
; i
++) {
3668 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
3669 state
->reply
[i
] = true;
3675 for (i
=0; i
<state
->node_count
; i
++) {
3676 if (! state
->reply
[i
]) {
3677 state
->done
= false;
3683 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3684 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3686 struct ctdb_disable_message disable
= { 0 };
3687 struct disable_recoveries_state state
;
3690 disable
.pnn
= ctdb
->pnn
;
3691 disable
.srvid
= next_srvid(ctdb
);
3692 disable
.timeout
= timeout
;
3694 state
.pnn_list
= pnn_list
;
3695 state
.node_count
= count
;
3698 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3699 if (state
.reply
== NULL
) {
3703 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3705 disable_recoveries_handler
,
3711 for (i
=0; i
<count
; i
++) {
3712 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3721 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3723 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3725 ret
= (state
.status
>= 0 ? 0 : 1);
3729 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3730 disable
.srvid
, &state
);
3734 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3735 int argc
, const char **argv
)
3737 struct ctdb_node_map
*nodemap
= NULL
;
3738 struct ctdb_node_map
*file_nodemap
;
3739 struct ctdb_node_map
*remote_nodemap
;
3740 struct ctdb_req_control request
;
3741 struct ctdb_reply_control
**reply
;
3748 nodemap
= get_nodemap(ctdb
, false);
3749 if (nodemap
== NULL
) {
3753 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3754 if (file_nodemap
== NULL
) {
3758 for (i
=0; i
<nodemap
->num
; i
++) {
3759 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3763 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3764 nodemap
->node
[i
].pnn
, TIMEOUT(),
3768 "ERROR: Failed to get nodes file from node %u\n",
3769 nodemap
->node
[i
].pnn
);
3773 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3775 "ERROR: Nodes file on node %u differs"
3776 " from current node (%u)\n",
3777 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3782 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3788 fprintf(stderr
, "No change in nodes file,"
3789 " skipping unnecessary reload\n");
3793 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3794 mem_ctx
, &pnn_list
);
3796 fprintf(stderr
, "Memory allocation error\n");
3800 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3803 fprintf(stderr
, "Failed to disable recoveries\n");
3807 ctdb_req_control_reload_nodes_file(&request
);
3808 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3809 pnn_list
, count
, TIMEOUT(),
3810 &request
, NULL
, &reply
);
3812 bool failed
= false;
3815 for (j
=0; j
<count
; j
++) {
3816 ret
= ctdb_reply_control_reload_nodes_file(reply
[j
]);
3819 "Node %u failed to reload nodes\n",
3826 "You MUST fix failed nodes manually!\n");
3830 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3832 fprintf(stderr
, "Failed to enable recoveries\n");
3839 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3840 ctdb_sock_addr
*addr
, uint32_t pnn
)
3842 struct ctdb_public_ip_list
*pubip_list
;
3843 struct ctdb_public_ip pubip
;
3844 struct ctdb_node_map
*nodemap
;
3845 struct ctdb_req_control request
;
3850 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3851 CTDB_BROADCAST_CONNECTED
,
3852 2*options
.timelimit
);
3854 fprintf(stderr
, "Failed to disable IP check\n");
3858 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3859 pnn
, TIMEOUT(), false, &pubip_list
);
3861 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3866 for (i
=0; i
<pubip_list
->num
; i
++) {
3867 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3872 if (i
== pubip_list
->num
) {
3873 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3874 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3878 nodemap
= get_nodemap(ctdb
, false);
3879 if (nodemap
== NULL
) {
3883 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3885 fprintf(stderr
, "Memory allocation error\n");
3891 ctdb_req_control_release_ip(&request
, &pubip
);
3893 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3894 pnn_list
, count
, TIMEOUT(),
3895 &request
, NULL
, NULL
);
3897 fprintf(stderr
, "Failed to release IP on nodes\n");
3901 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3902 pnn
, TIMEOUT(), &pubip
);
3904 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3911 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3912 int argc
, const char **argv
)
3914 ctdb_sock_addr addr
;
3923 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3925 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3929 pnn
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3930 if (pnn
== CTDB_UNKNOWN_PNN
|| ret
!= 0) {
3931 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3935 while (retries
< 5) {
3936 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3946 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3954 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3959 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3960 CTDB_BROADCAST_CONNECTED
, pnn
);
3963 "Failed to ask leader to distribute IPs\n");
3970 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3971 int argc
, const char **argv
)
3973 ctdb_sock_addr addr
;
3974 struct ctdb_public_ip_list
*pubip_list
;
3975 struct ctdb_addr_info addr_info
;
3976 unsigned int mask
, i
;
3977 int ret
, retries
= 0;
3983 ret
= ctdb_sock_addr_mask_from_string(argv
[0], &addr
, &mask
);
3985 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3989 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3990 ctdb
->cmd_pnn
, TIMEOUT(),
3991 false, &pubip_list
);
3993 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3998 for (i
=0; i
<pubip_list
->num
; i
++) {
3999 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
4000 fprintf(stderr
, "Node already knows about IP %s\n",
4001 ctdb_sock_addr_to_string(mem_ctx
,
4007 addr_info
.addr
= addr
;
4008 addr_info
.mask
= mask
;
4009 addr_info
.iface
= argv
[1];
4011 while (retries
< 5) {
4012 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4013 ctdb
->cmd_pnn
, TIMEOUT(),
4024 fprintf(stderr
, "Failed to add public IP to node %u."
4025 " Giving up\n", ctdb
->cmd_pnn
);
4029 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
4037 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4038 int argc
, const char **argv
)
4040 ctdb_sock_addr addr
;
4041 struct ctdb_public_ip_list
*pubip_list
;
4042 struct ctdb_addr_info addr_info
;
4050 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
4052 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
4056 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4057 ctdb
->cmd_pnn
, TIMEOUT(),
4058 false, &pubip_list
);
4060 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
4065 for (i
=0; i
<pubip_list
->num
; i
++) {
4066 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
4071 if (i
== pubip_list
->num
) {
4072 fprintf(stderr
, "Node does not know about IP address %s\n",
4073 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
4077 addr_info
.addr
= addr
;
4079 addr_info
.iface
= NULL
;
4081 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4082 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
4084 fprintf(stderr
, "Failed to delete public IP from node %u\n",
4092 #define DB_VERSION 3
4093 #define MAX_DB_NAME 64
4094 #define MAX_REC_BUFFER_SIZE (100*1000)
4097 unsigned long version
;
4099 unsigned long flags
;
4102 char name
[MAX_DB_NAME
];
4105 struct backup_state
{
4106 TALLOC_CTX
*mem_ctx
;
4107 struct ctdb_rec_buffer
*recbuf
;
4110 unsigned int nbuf
, nrec
;
4113 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
4114 TDB_DATA key
, TDB_DATA data
, void *private_data
)
4116 struct backup_state
*state
= (struct backup_state
*)private_data
;
4120 if (state
->recbuf
== NULL
) {
4121 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4123 if (state
->recbuf
== NULL
) {
4128 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4134 len
= ctdb_rec_buffer_len(state
->recbuf
);
4135 if (len
< MAX_REC_BUFFER_SIZE
) {
4139 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4141 fprintf(stderr
, "Failed to write records to backup file\n");
4146 state
->nrec
+= state
->recbuf
->count
;
4147 TALLOC_FREE(state
->recbuf
);
4152 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4153 int argc
, const char **argv
)
4155 const char *db_name
;
4156 struct ctdb_db_context
*db
;
4159 struct backup_state state
;
4160 struct db_header db_hdr
;
4167 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4171 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4174 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4178 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4181 fprintf(stderr
, "Failed to open file %s for writing\n",
4186 /* Write empty header first */
4187 ZERO_STRUCT(db_hdr
);
4188 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4192 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4196 state
.mem_ctx
= mem_ctx
;
4197 state
.recbuf
= NULL
;
4202 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4204 fprintf(stderr
, "Failed to collect records from DB %s\n",
4210 if (state
.recbuf
!= NULL
) {
4211 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4214 "Failed to write records to backup file\n");
4220 state
.nrec
+= state
.recbuf
->count
;
4221 TALLOC_FREE(state
.recbuf
);
4224 db_hdr
.version
= DB_VERSION
;
4225 db_hdr
.timestamp
= time(NULL
);
4226 db_hdr
.flags
= db_flags
;
4227 db_hdr
.nbuf
= state
.nbuf
;
4228 db_hdr
.nrec
= state
.nrec
;
4229 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4231 lseek(fd
, 0, SEEK_SET
);
4232 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4236 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4241 printf("Database backed up to %s\n", argv
[1]);
4245 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4246 int argc
, const char **argv
)
4248 const char *db_name
= NULL
;
4249 struct ctdb_db_context
*db
;
4250 struct db_header db_hdr
;
4251 struct ctdb_node_map
*nodemap
;
4252 struct ctdb_req_control request
;
4253 struct ctdb_reply_control
**reply
;
4254 struct ctdb_transdb wipedb
;
4255 struct ctdb_pulldb_ext pulldb
;
4256 struct ctdb_rec_buffer
*recbuf
;
4257 uint32_t generation
;
4262 unsigned long i
, count
;
4266 if (argc
< 1 || argc
> 2) {
4270 fd
= open(argv
[0], O_RDONLY
, 0600);
4273 fprintf(stderr
, "Failed to open file %s for reading\n",
4282 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4286 fprintf(stderr
, "Failed to read db header from file %s\n",
4290 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4292 if (db_hdr
.version
!= DB_VERSION
) {
4294 "Wrong version of backup file, expected %u, got %lu\n",
4295 DB_VERSION
, db_hdr
.version
);
4300 if (db_name
== NULL
) {
4301 db_name
= db_hdr
.name
;
4304 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4305 localtime(&db_hdr
.timestamp
));
4306 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4308 db_flags
= db_hdr
.flags
& 0xff;
4309 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4312 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4317 nodemap
= get_nodemap(ctdb
, false);
4318 if (nodemap
== NULL
) {
4319 fprintf(stderr
, "Failed to get nodemap\n");
4324 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4326 fprintf(stderr
, "Failed to get current generation\n");
4331 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4338 wipedb
.db_id
= ctdb_db_id(db
);
4339 wipedb
.tid
= generation
;
4341 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4342 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4343 ctdb
->client
, pnn_list
, count
,
4344 TIMEOUT(), &request
, NULL
, NULL
);
4350 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4351 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4352 pnn_list
, count
, TIMEOUT(),
4353 &request
, NULL
, NULL
);
4358 ctdb_req_control_wipe_database(&request
, &wipedb
);
4359 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4360 pnn_list
, count
, TIMEOUT(),
4361 &request
, NULL
, NULL
);
4366 pulldb
.db_id
= ctdb_db_id(db
);
4368 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4370 ctdb_req_control_db_push_start(&request
, &pulldb
);
4371 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4372 pnn_list
, count
, TIMEOUT(),
4373 &request
, NULL
, NULL
);
4378 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4379 struct ctdb_req_message message
;
4383 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4388 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4389 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4390 if (data
.dptr
== NULL
) {
4394 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4396 message
.srvid
= pulldb
.srvid
;
4397 message
.data
.data
= data
;
4399 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4407 talloc_free(recbuf
);
4408 talloc_free(data
.dptr
);
4411 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4412 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4413 pnn_list
, count
, TIMEOUT(),
4414 &request
, NULL
, &reply
);
4419 for (i
=0; i
<count
; i
++) {
4420 uint32_t num_records
;
4422 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4425 fprintf(stderr
, "Invalid response from node %u\n",
4430 if (num_records
!= db_hdr
.nrec
) {
4431 fprintf(stderr
, "Node %u received %u of %lu records\n",
4432 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4437 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4438 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4439 pnn_list
, count
, TIMEOUT(),
4440 &request
, NULL
, NULL
);
4445 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4446 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4447 pnn_list
, count
, TIMEOUT(),
4448 &request
, NULL
, NULL
);
4453 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4454 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4455 ctdb
->client
, pnn_list
, count
,
4456 TIMEOUT(), &request
, NULL
, NULL
);
4461 printf("Database %s restored\n", db_name
);
4468 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4469 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4473 struct dumpdbbackup_state
{
4474 ctdb_rec_parser_func_t parser
;
4475 struct dump_record_state sub_state
;
4478 static int dumpdbbackup_handler(uint32_t reqid
,
4479 struct ctdb_ltdb_header
*header
,
4480 TDB_DATA key
, TDB_DATA data
,
4483 struct dumpdbbackup_state
*state
=
4484 (struct dumpdbbackup_state
*)private_data
;
4485 struct ctdb_ltdb_header hdr
;
4488 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4493 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4496 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4497 int argc
, const char **argv
)
4499 struct db_header db_hdr
;
4501 struct dumpdbbackup_state state
;
4507 usage("dumpbackup");
4510 fd
= open(argv
[0], O_RDONLY
, 0600);
4513 fprintf(stderr
, "Failed to open file %s for reading\n",
4518 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4522 fprintf(stderr
, "Failed to read db header from file %s\n",
4526 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4528 if (db_hdr
.version
!= DB_VERSION
) {
4530 "Wrong version of backup file, expected %u, got %lu\n",
4531 DB_VERSION
, db_hdr
.version
);
4536 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4537 localtime(&db_hdr
.timestamp
));
4538 printf("Dumping database %s from backup @ %s\n",
4539 db_hdr
.name
, timebuf
);
4541 state
.parser
= dump_record
;
4542 state
.sub_state
.count
= 0;
4544 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4545 struct ctdb_rec_buffer
*recbuf
;
4547 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4549 fprintf(stderr
, "Failed to read records\n");
4554 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4557 fprintf(stderr
, "Failed to dump records\n");
4564 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4568 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4569 int argc
, const char **argv
)
4571 const char *db_name
;
4572 struct ctdb_db_context
*db
;
4575 struct ctdb_node_map
*nodemap
;
4576 struct ctdb_req_control request
;
4577 struct ctdb_transdb wipedb
;
4578 uint32_t generation
;
4586 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4590 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4593 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4597 nodemap
= get_nodemap(ctdb
, false);
4598 if (nodemap
== NULL
) {
4599 fprintf(stderr
, "Failed to get nodemap\n");
4603 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4605 fprintf(stderr
, "Failed to get current generation\n");
4609 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4615 ctdb_req_control_db_freeze(&request
, db_id
);
4616 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4617 ctdb
->client
, pnn_list
, count
,
4618 TIMEOUT(), &request
, NULL
, NULL
);
4623 wipedb
.db_id
= db_id
;
4624 wipedb
.tid
= generation
;
4626 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4627 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4628 pnn_list
, count
, TIMEOUT(),
4629 &request
, NULL
, NULL
);
4634 ctdb_req_control_wipe_database(&request
, &wipedb
);
4635 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4636 pnn_list
, count
, TIMEOUT(),
4637 &request
, NULL
, NULL
);
4642 ctdb_req_control_db_set_healthy(&request
, db_id
);
4643 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4644 pnn_list
, count
, TIMEOUT(),
4645 &request
, NULL
, NULL
);
4650 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4651 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4652 pnn_list
, count
, TIMEOUT(),
4653 &request
, NULL
, NULL
);
4658 ctdb_req_control_db_thaw(&request
, db_id
);
4659 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4660 ctdb
->client
, pnn_list
, count
,
4661 TIMEOUT(), &request
, NULL
, NULL
);
4666 printf("Database %s wiped\n", db_name
);
4671 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4672 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4676 static int control_leader(TALLOC_CTX
*mem_ctx
,
4677 struct ctdb_context
*ctdb
,
4684 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
4694 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4695 int argc
, const char **argv
)
4697 char *t
, *event_helper
= NULL
;
4699 t
= getenv("CTDB_EVENT_HELPER");
4701 event_helper
= talloc_strdup(mem_ctx
, t
);
4703 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb-event",
4704 CTDB_HELPER_BINDIR
);
4707 if (event_helper
== NULL
) {
4708 fprintf(stderr
, "Unable to set event daemon helper\n");
4712 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4716 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4717 int argc
, const char **argv
)
4719 const char *new_argv
[4];
4722 usage("scriptstatus");
4725 new_argv
[0] = "status";
4726 new_argv
[1] = "legacy";
4727 new_argv
[2] = (argc
== 0) ? "monitor" : argv
[0];
4730 (void) control_event(mem_ctx
, ctdb
, 3, new_argv
);
4734 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4735 int argc
, const char **argv
)
4737 char *t
, *natgw_helper
= NULL
;
4743 t
= getenv("CTDB_NATGW_HELPER");
4745 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4747 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4748 CTDB_HELPER_BINDIR
);
4751 if (natgw_helper
== NULL
) {
4752 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4756 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4761 * Find the PNN of the current node
4762 * discover the pnn by loading the nodes file and try to bind
4763 * to all addresses one at a time until the ip address is found.
4765 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4767 struct ctdb_node_map
*nodemap
;
4770 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4771 if (nodemap
== NULL
) {
4775 for (i
=0; i
<nodemap
->num
; i
++) {
4776 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4779 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4781 *pnn
= nodemap
->node
[i
].pnn
;
4783 talloc_free(nodemap
);
4788 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4789 talloc_free(nodemap
);
4793 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4794 int argc
, const char **argv
)
4796 const char *reclock
;
4800 usage("getreclock");
4803 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4804 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4809 if (reclock
!= NULL
) {
4810 printf("%s\n", reclock
);
4816 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4817 struct ctdb_context
*ctdb
,
4818 int argc
, const char **argv
)
4820 uint32_t lmasterrole
= 0;
4824 usage("setlmasterrole");
4827 if (strcmp(argv
[0], "on") == 0) {
4829 } else if (strcmp(argv
[0], "off") == 0) {
4832 usage("setlmasterrole");
4835 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4836 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4844 static int control_setleaderrole(TALLOC_CTX
*mem_ctx
,
4845 struct ctdb_context
*ctdb
,
4849 uint32_t leaderrole
= 0;
4853 usage("setleaderrole");
4856 if (strcmp(argv
[0], "on") == 0) {
4858 } else if (strcmp(argv
[0], "off") == 0) {
4861 usage("setleaderrole");
4864 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
,
4877 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4878 struct ctdb_context
*ctdb
,
4879 int argc
, const char **argv
)
4886 usage("setdbreadonly");
4889 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4893 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4894 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4898 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4899 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4907 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4908 int argc
, const char **argv
)
4915 usage("setdbsticky");
4918 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4922 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4923 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4927 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4928 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4936 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4937 int argc
, const char **argv
)
4939 const char *db_name
;
4940 struct ctdb_db_context
*db
;
4941 struct ctdb_transaction_handle
*h
;
4950 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4955 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4956 fprintf(stderr
, "Transactions not supported on DB %s\n",
4961 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4964 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4968 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4970 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4974 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4975 TIMEOUT(), db
, true, &h
);
4977 fprintf(stderr
, "Failed to start transaction on db %s\n",
4982 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4984 fprintf(stderr
, "Failed to read record for key %s\n",
4986 ctdb_transaction_cancel(h
);
4990 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4992 ctdb_transaction_cancel(h
);
4996 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4997 int argc
, const char **argv
)
4999 const char *db_name
;
5000 struct ctdb_db_context
*db
;
5001 struct ctdb_transaction_handle
*h
;
5010 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5015 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5016 fprintf(stderr
, "Transactions not supported on DB %s\n",
5021 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5024 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5028 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5030 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5034 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5036 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5040 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5041 TIMEOUT(), db
, false, &h
);
5043 fprintf(stderr
, "Failed to start transaction on db %s\n",
5048 ret
= ctdb_transaction_store_record(h
, key
, data
);
5050 fprintf(stderr
, "Failed to store record for key %s\n",
5052 ctdb_transaction_cancel(h
);
5056 ret
= ctdb_transaction_commit(h
);
5058 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5060 ctdb_transaction_cancel(h
);
5067 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5068 int argc
, const char **argv
)
5070 const char *db_name
;
5071 struct ctdb_db_context
*db
;
5072 struct ctdb_transaction_handle
*h
;
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",
5092 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5095 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5099 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5101 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5105 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5106 TIMEOUT(), db
, false, &h
);
5108 fprintf(stderr
, "Failed to start transaction on db %s\n",
5113 ret
= ctdb_transaction_delete_record(h
, key
);
5115 fprintf(stderr
, "Failed to delete record for key %s\n",
5117 ctdb_transaction_cancel(h
);
5121 ret
= ctdb_transaction_commit(h
);
5123 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5125 ctdb_transaction_cancel(h
);
5132 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5140 /* Skip whitespace */
5141 n
= strspn(*ptr
, " \t");
5145 /* Quoted ASCII string - no wide characters! */
5147 n
= strcspn(t
, "\"");
5150 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5157 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5161 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5168 #define MAX_LINE_SIZE 1024
5170 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5171 TDB_DATA
*key
, TDB_DATA
*value
)
5173 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5177 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5183 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5184 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5185 /* Line Ignored but not EOF */
5191 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5193 /* Line Ignored but not EOF */
5194 talloc_free(key
->dptr
);
5202 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5203 int argc
, const char **argv
)
5205 const char *db_name
;
5206 struct ctdb_db_context
*db
;
5207 struct ctdb_transaction_handle
*h
;
5210 TDB_DATA key
= tdb_null
, value
= tdb_null
;
5213 if (argc
< 1 || argc
> 2) {
5217 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5222 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5223 fprintf(stderr
, "Transactions not supported on DB %s\n",
5229 file
= fopen(argv
[1], "r");
5231 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5238 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5241 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5245 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5246 TIMEOUT(), db
, false, &h
);
5248 fprintf(stderr
, "Failed to start transaction on db %s\n",
5253 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5254 if (key
.dsize
!= 0) {
5255 ret
= ctdb_transaction_store_record(h
, key
, value
);
5257 fprintf(stderr
, "Failed to store record\n");
5258 ctdb_transaction_cancel(h
);
5261 talloc_free(key
.dptr
);
5262 talloc_free(value
.dptr
);
5266 ret
= ctdb_transaction_commit(h
);
5268 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5270 ctdb_transaction_cancel(h
);
5274 if (file
!= stdin
) {
5280 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5281 int argc
, const char **argv
)
5283 struct tdb_context
*tdb
;
5285 struct ctdb_ltdb_header header
;
5288 if (argc
< 2 || argc
> 3) {
5292 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5294 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5298 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5300 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5305 data
= tdb_fetch(tdb
, key
);
5306 if (data
.dptr
== NULL
) {
5307 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5312 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5313 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5324 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5326 fprintf(stderr
, "Failed to open output file %s\n",
5331 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5332 if (nwritten
== -1 ||
5333 (size_t)nwritten
!= data
.dsize
) {
5334 fprintf(stderr
, "Failed to write record to file\n");
5343 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5345 fprintf(stderr
, "Failed to parse header from data\n");
5349 dump_ltdb_header(&header
);
5350 dump_tdb_data("data", data
);
5355 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5356 int argc
, const char **argv
)
5358 struct tdb_context
*tdb
;
5359 TDB_DATA key
, data
[2], value
;
5360 struct ctdb_ltdb_header header
;
5361 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5365 if (argc
< 3 || argc
> 5) {
5369 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5371 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5375 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5377 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5382 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5384 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5389 ZERO_STRUCT(header
);
5392 header
.rsn
= (uint64_t)smb_strtoull(argv
[3],
5402 header
.dmaster
= (uint32_t)atol(argv
[4]);
5405 header
.flags
= (uint32_t)atol(argv
[5]);
5408 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5411 data
[0].dptr
= header_buf
;
5413 data
[1].dsize
= value
.dsize
;
5414 data
[1].dptr
= value
.dptr
;
5416 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5418 fprintf(stderr
, "Failed to write record %s to file %s\n",
5427 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5428 int argc
, const char **argv
)
5430 const char *db_name
;
5431 struct ctdb_db_context
*db
;
5432 struct ctdb_record_handle
*h
;
5435 bool readonly
= false;
5438 if (argc
< 2 || argc
> 3) {
5443 if (strcmp(argv
[2], "readonly") == 0) {
5450 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5454 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5455 fprintf(stderr
, "DB %s is not a volatile database\n",
5460 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5463 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5467 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5469 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5473 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5474 db
, key
, readonly
, &h
, NULL
, &data
);
5476 fprintf(stderr
, "Failed to read record for key %s\n",
5479 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5480 (int)data
.dsize
, data
.dptr
);
5487 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5488 int argc
, const char **argv
)
5490 const char *db_name
;
5491 struct ctdb_db_context
*db
;
5492 struct ctdb_record_handle
*h
;
5501 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5505 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5506 fprintf(stderr
, "DB %s is not a volatile database\n",
5511 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5514 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5518 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5520 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5524 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5526 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5530 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5531 db
, key
, false, &h
, NULL
, NULL
);
5533 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5537 ret
= ctdb_store_record(h
, data
);
5539 fprintf(stderr
, "Failed to store record for key %s\n",
5547 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5548 int argc
, const char **argv
)
5550 const char *db_name
;
5551 struct ctdb_db_context
*db
;
5552 struct ctdb_record_handle
*h
;
5561 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5565 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5566 fprintf(stderr
, "DB %s is not a volatile database\n",
5571 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5574 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5578 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5580 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5584 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5585 db
, key
, false, &h
, NULL
, &data
);
5587 fprintf(stderr
, "Failed to fetch record for key %s\n",
5592 ret
= ctdb_delete_record(h
);
5594 fprintf(stderr
, "Failed to delete record for key %s\n",
5602 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5603 int argc
, const char **argv
)
5605 struct sockaddr_in sin
;
5611 usage("chktcpport");
5614 port
= atoi(argv
[0]);
5616 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5618 fprintf(stderr
, "Failed to open local socket\n");
5622 v
= fcntl(s
, F_GETFL
, 0);
5623 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5624 fprintf(stderr
, "Unable to set socket non-blocking\n");
5629 bzero(&sin
, sizeof(sin
));
5630 sin
.sin_family
= AF_INET
;
5631 sin
.sin_port
= htons(port
);
5632 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5635 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5642 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5643 int argc
, const char **argv
)
5646 const char *db_name
;
5651 usage("getdbseqnum");
5654 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5658 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5659 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5662 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5667 printf("0x%"PRIx64
"\n", seqnum
);
5671 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5672 int argc
, const char **argv
)
5674 const char *nodestring
= NULL
;
5675 struct ctdb_node_map
*nodemap_in
;
5676 struct ctdb_node_map
*nodemap
;
5679 bool print_hdr
= false;
5682 usage("nodestatus");
5686 nodestring
= argv
[0];
5687 if (strcmp(nodestring
, "all") == 0) {
5692 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap_in
)) {
5696 nodemap
= get_nodemap_unknown(mem_ctx
, ctdb
, nodemap_in
);
5697 if (nodemap
== NULL
) {
5701 if (options
.machinereadable
) {
5702 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5704 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5708 for (i
=0; i
<nodemap
->num
; i
++) {
5709 uint32_t flags
= nodemap
->node
[i
].flags
;
5711 if ((flags
& NODE_FLAGS_DELETED
) != 0) {
5724 } db_stats_fields
[] = {
5725 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5726 DBSTATISTICS_FIELD(db_ro_delegations
),
5727 DBSTATISTICS_FIELD(db_ro_revokes
),
5728 DBSTATISTICS_FIELD(locks
.num_calls
),
5729 DBSTATISTICS_FIELD(locks
.num_current
),
5730 DBSTATISTICS_FIELD(locks
.num_pending
),
5731 DBSTATISTICS_FIELD(locks
.num_failed
),
5734 static void print_dbstatistics(const char *db_name
,
5735 struct ctdb_db_statistics
*s
)
5738 const char *prefix
= NULL
;
5741 printf("DB Statistics %s\n", db_name
);
5743 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5744 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5745 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5747 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5748 prefix
= db_stats_fields
[i
].name
;
5749 printf(" %*.*s\n", preflen
-1, preflen
-1,
5750 db_stats_fields
[i
].name
);
5755 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5756 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5757 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5760 printf(" hop_count_buckets:");
5761 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5762 printf(" %d", s
->hop_count_bucket
[i
]);
5766 printf(" lock_buckets:");
5767 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5768 printf(" %d", s
->locks
.buckets
[i
]);
5772 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5773 "locks_latency MIN/AVG/MAX",
5774 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5775 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5777 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5778 "vacuum_latency MIN/AVG/MAX",
5779 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5780 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5782 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5783 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5785 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5786 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5787 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5793 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5794 int argc
, const char **argv
)
5797 const char *db_name
;
5798 struct ctdb_db_statistics
*dbstats
;
5802 usage("dbstatistics");
5805 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5809 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5810 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5813 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5818 print_dbstatistics(db_name
, dbstats
);
5822 struct disable_takeover_runs_state
{
5824 unsigned int node_count
;
5830 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5833 struct disable_takeover_runs_state
*state
=
5834 (struct disable_takeover_runs_state
*)private_data
;
5838 if (data
.dsize
!= sizeof(int)) {
5843 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5844 ret
= *(int *)data
.dptr
;
5846 state
->status
= ret
;
5850 for (i
=0; i
<state
->node_count
; i
++) {
5851 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
5852 state
->reply
[i
] = true;
5858 for (i
=0; i
<state
->node_count
; i
++) {
5859 if (! state
->reply
[i
]) {
5860 state
->done
= false;
5866 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5867 struct ctdb_context
*ctdb
, uint32_t timeout
,
5868 uint32_t *pnn_list
, int count
)
5870 struct ctdb_disable_message disable
= { 0 };
5871 struct disable_takeover_runs_state state
;
5874 disable
.pnn
= ctdb
->pnn
;
5875 disable
.srvid
= next_srvid(ctdb
);
5876 disable
.timeout
= timeout
;
5878 state
.pnn_list
= pnn_list
;
5879 state
.node_count
= count
;
5882 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5883 if (state
.reply
== NULL
) {
5887 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5889 disable_takeover_run_handler
,
5895 for (i
=0; i
<count
; i
++) {
5896 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5905 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5907 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5909 ret
= (state
.status
>= 0 ? 0 : 1);
5913 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5914 disable
.srvid
, &state
);
5918 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5919 int argc
, const char **argv
)
5921 const char *nodestring
= NULL
;
5922 struct ctdb_node_map
*nodemap
, *nodemap2
;
5923 struct ctdb_req_control request
;
5924 uint32_t *pnn_list
, *pnn_list2
;
5925 int ret
, count
, count2
;
5932 nodestring
= argv
[0];
5935 nodemap
= get_nodemap(ctdb
, false);
5936 if (nodemap
== NULL
) {
5940 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5944 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5945 mem_ctx
, &pnn_list
);
5947 fprintf(stderr
, "Memory allocation error\n");
5951 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5952 mem_ctx
, &pnn_list2
);
5954 fprintf(stderr
, "Memory allocation error\n");
5958 /* Disable takeover runs on all connected nodes. A reply
5959 * indicating success is needed from each node so all nodes
5960 * will need to be active.
5962 * A check could be added to not allow reloading of IPs when
5963 * there are disconnected nodes. However, this should
5964 * probably be left up to the administrator.
5966 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5969 fprintf(stderr
, "Failed to disable takeover runs\n");
5973 /* Now tell all the desired nodes to reload their public IPs.
5974 * Keep trying this until it succeeds. This assumes all
5975 * failures are transient, which might not be true...
5977 ctdb_req_control_reload_public_ips(&request
);
5978 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5979 pnn_list2
, count2
, TIMEOUT(),
5980 &request
, NULL
, NULL
);
5982 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5985 /* It isn't strictly necessary to wait until takeover runs are
5986 * re-enabled but doing so can't hurt.
5988 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5990 fprintf(stderr
, "Failed to enable takeover runs\n");
5994 return ipreallocate(mem_ctx
, ctdb
);
5998 static const struct ctdb_cmd
{
6000 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
6001 bool without_daemon
; /* can be run without daemon running ? */
6002 bool remote
; /* can be run on remote nodes */
6005 } ctdb_commands
[] = {
6006 { "version", control_version
, true, false,
6007 "show version of ctdb", NULL
},
6008 { "status", control_status
, false, true,
6009 "show node status", NULL
},
6010 { "uptime", control_uptime
, false, true,
6011 "show node uptime", NULL
},
6012 { "ping", control_ping
, false, true,
6013 "ping a node", NULL
},
6014 { "runstate", control_runstate
, false, true,
6015 "get/check runstate of a node",
6016 "[setup|first_recovery|startup|running]" },
6017 { "getvar", control_getvar
, false, true,
6018 "get a tunable variable", "<name>" },
6019 { "setvar", control_setvar
, false, true,
6020 "set a tunable variable", "<name> <value>" },
6021 { "listvars", control_listvars
, false, true,
6022 "list tunable variables", NULL
},
6023 { "statistics", control_statistics
, false, true,
6024 "show ctdb statistics", NULL
},
6025 { "statisticsreset", control_statistics_reset
, false, true,
6026 "reset ctdb statistics", NULL
},
6027 { "stats", control_stats
, false, true,
6028 "show rolling statistics", "[count]" },
6029 { "ip", control_ip
, false, true,
6030 "show public ips", "[all]" },
6031 { "ipinfo", control_ipinfo
, false, true,
6032 "show public ip details", "<ip>" },
6033 { "ifaces", control_ifaces
, false, true,
6034 "show interfaces", NULL
},
6035 { "setifacelink", control_setifacelink
, false, true,
6036 "set interface link status", "<iface> up|down" },
6037 { "process-exists", control_process_exists
, false, true,
6038 "check if a process exists on a node", "<pid> [<srvid>]" },
6039 { "getdbmap", control_getdbmap
, false, true,
6040 "show attached databases", NULL
},
6041 { "getdbstatus", control_getdbstatus
, false, true,
6042 "show database status", "<dbname|dbid>" },
6043 { "catdb", control_catdb
, false, false,
6044 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6045 { "cattdb", control_cattdb
, false, false,
6046 "dump local ctdb database", "<dbname|dbid>" },
6047 { "getcapabilities", control_getcapabilities
, false, true,
6048 "show node capabilities", NULL
},
6049 { "pnn", control_pnn
, false, false,
6050 "show the pnn of the current node", NULL
},
6051 { "lvs", control_lvs
, false, false,
6052 "show lvs configuration", "leader|list|status" },
6053 { "setdebug", control_setdebug
, false, true,
6054 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6055 { "getdebug", control_getdebug
, false, true,
6056 "get debug level", NULL
},
6057 { "attach", control_attach
, false, false,
6058 "attach a database", "<dbname> [persistent|replicated]" },
6059 { "detach", control_detach
, false, false,
6060 "detach database(s)", "<dbname|dbid> ..." },
6061 { "dumpmemory", control_dumpmemory
, false, true,
6062 "dump ctdbd memory map", NULL
},
6063 { "rddumpmemory", control_rddumpmemory
, false, true,
6064 "dump recoverd memory map", NULL
},
6065 { "getpid", control_getpid
, false, true,
6066 "get ctdbd process ID", NULL
},
6067 { "disable", control_disable
, false, true,
6068 "disable a node", NULL
},
6069 { "enable", control_enable
, false, true,
6070 "enable a node", NULL
},
6071 { "stop", control_stop
, false, true,
6072 "stop a node", NULL
},
6073 { "continue", control_continue
, false, true,
6074 "continue a stopped node", NULL
},
6075 { "ban", control_ban
, false, true,
6076 "ban a node", "<bantime>"},
6077 { "unban", control_unban
, false, true,
6078 "unban a node", NULL
},
6079 { "shutdown", control_shutdown
, false, true,
6080 "shutdown ctdb daemon", NULL
},
6081 { "recover", control_recover
, false, true,
6082 "force recovery", NULL
},
6083 { "sync", control_ipreallocate
, false, true,
6084 "run ip reallocation (deprecated)", NULL
},
6085 { "ipreallocate", control_ipreallocate
, false, true,
6086 "run ip reallocation", NULL
},
6087 { "gratarp", control_gratarp
, false, true,
6088 "send a gratuitous arp", "<ip> <interface>" },
6089 { "tickle", control_tickle
, true, false,
6090 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6091 { "gettickles", control_gettickles
, false, true,
6092 "get the list of tickles", "<ip> [<port>]" },
6093 { "addtickle", control_addtickle
, false, true,
6094 "add a tickle", "<ip>:<port> <ip>:<port>" },
6095 { "deltickle", control_deltickle
, false, true,
6096 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6097 { "listnodes", control_listnodes
, true, true,
6098 "list nodes in the cluster", NULL
},
6099 { "reloadnodes", control_reloadnodes
, false, false,
6100 "reload the nodes file all nodes", NULL
},
6101 { "moveip", control_moveip
, false, false,
6102 "move an ip address to another node", "<ip> <node>" },
6103 { "addip", control_addip
, false, true,
6104 "add an ip address to a node", "<ip/mask> <iface>" },
6105 { "delip", control_delip
, false, true,
6106 "delete an ip address from a node", "<ip>" },
6107 { "backupdb", control_backupdb
, false, false,
6108 "backup a database into a file", "<dbname|dbid> <file>" },
6109 { "restoredb", control_restoredb
, false, false,
6110 "restore a database from a file", "<file> [dbname]" },
6111 { "dumpdbbackup", control_dumpdbbackup
, true, false,
6112 "dump database from a backup file", "<file>" },
6113 { "wipedb", control_wipedb
, false, false,
6114 "wipe the contents of a database.", "<dbname|dbid>"},
6115 { "leader", control_leader
, false, true,
6116 "show the pnn of the leader", NULL
},
6117 { "event", control_event
, true, false,
6118 "event and event script commands", NULL
},
6119 { "scriptstatus", control_scriptstatus
, true, false,
6120 "show event script status",
6121 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6122 { "natgw", control_natgw
, false, false,
6123 "show natgw configuration", "leader|list|status" },
6124 { "getreclock", control_getreclock
, false, true,
6125 "get recovery lock file", NULL
},
6126 { "setlmasterrole", control_setlmasterrole
, false, true,
6127 "set LMASTER role", "on|off" },
6128 { "setleaderrole", control_setleaderrole
, false, true,
6129 "set LEADER role", "on|off"},
6130 { "setdbreadonly", control_setdbreadonly
, false, true,
6131 "enable readonly records", "<dbname|dbid>" },
6132 { "setdbsticky", control_setdbsticky
, false, true,
6133 "enable sticky records", "<dbname|dbid>"},
6134 { "pfetch", control_pfetch
, false, false,
6135 "fetch record from persistent database", "<dbname|dbid> <key>" },
6136 { "pstore", control_pstore
, false, false,
6137 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6138 { "pdelete", control_pdelete
, false, false,
6139 "delete record from persistent database", "<dbname|dbid> <key>" },
6140 { "ptrans", control_ptrans
, false, false,
6141 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6142 { "tfetch", control_tfetch
, false, true,
6143 "fetch a record", "<tdb-file> <key> [<file>]" },
6144 { "tstore", control_tstore
, false, true,
6145 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6146 { "readkey", control_readkey
, false, false,
6147 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6148 { "writekey", control_writekey
, false, false,
6149 "write value for a database key", "<dbname|dbid> <key> <value>" },
6150 { "deletekey", control_deletekey
, false, false,
6151 "delete a database key", "<dbname|dbid> <key>" },
6152 { "checktcpport", control_checktcpport
, true, false,
6153 "check if a service is bound to a specific tcp port or not", "<port>" },
6154 { "getdbseqnum", control_getdbseqnum
, false, false,
6155 "get database sequence number", "<dbname|dbid>" },
6156 { "nodestatus", control_nodestatus
, false, true,
6157 "show and return node status", "[all|<pnn-list>]" },
6158 { "dbstatistics", control_dbstatistics
, false, true,
6159 "show database statistics", "<dbname|dbid>" },
6160 { "reloadips", control_reloadips
, false, false,
6161 "reload the public addresses file", "[all|<pnn-list>]" },
6164 static const struct ctdb_cmd
*match_command(const char *command
)
6166 const struct ctdb_cmd
*cmd
;
6169 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6170 cmd
= &ctdb_commands
[i
];
6171 if (strlen(command
) == strlen(cmd
->name
) &&
6172 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6182 * Show usage message
6184 static void usage_full(void)
6188 poptPrintHelp(pc
, stdout
, 0);
6189 printf("\nCommands:\n");
6190 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6191 printf(" %-15s %-27s %s\n",
6192 ctdb_commands
[i
].name
,
6193 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6194 ctdb_commands
[i
].msg
);
6198 static void usage(const char *command
)
6200 const struct ctdb_cmd
*cmd
;
6202 if (command
== NULL
) {
6207 cmd
= match_command(command
);
6211 poptPrintUsage(pc
, stdout
, 0);
6212 printf("\nCommands:\n");
6213 printf(" %-15s %-27s %s\n",
6214 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6220 struct poptOption cmdline_options
[] = {
6223 .longName
= "debug",
6225 .argInfo
= POPT_ARG_STRING
,
6226 .arg
= &options
.debuglevelstr
,
6228 .descrip
= "debug level",
6231 .longName
= "timelimit",
6233 .argInfo
= POPT_ARG_INT
,
6234 .arg
= &options
.timelimit
,
6236 .descrip
= "timelimit (in seconds)",
6241 .argInfo
= POPT_ARG_INT
,
6242 .arg
= &options
.pnn
,
6244 .descrip
= "node specification - integer",
6249 .argInfo
= POPT_ARG_NONE
,
6250 .arg
= &options
.machinereadable
,
6252 .descrip
= "enable machine readable output",
6255 .longName
= "separator",
6257 .argInfo
= POPT_ARG_STRING
,
6258 .arg
= &options
.sep
,
6260 .descrip
= "specify separator for machine readable output",
6261 .argDescrip
= "CHAR",
6265 .argInfo
= POPT_ARG_NONE
,
6266 .arg
= &options
.machineparsable
,
6268 .descrip
= "enable machine parsable output with separator |",
6271 .longName
= "verbose",
6273 .argInfo
= POPT_ARG_NONE
,
6274 .arg
= &options
.verbose
,
6276 .descrip
= "enable verbose output",
6279 .longName
= "maxruntime",
6281 .argInfo
= POPT_ARG_INT
,
6282 .arg
= &options
.maxruntime
,
6284 .descrip
= "die if runtime exceeds this limit (in seconds)",
6289 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6292 TALLOC_CTX
*tmp_ctx
;
6293 struct ctdb_context
*ctdb
;
6294 const char *ctdb_socket
;
6297 uint64_t srvid_offset
;
6299 tmp_ctx
= talloc_new(NULL
);
6300 if (tmp_ctx
== NULL
) {
6301 fprintf(stderr
, "Memory allocation error\n");
6305 if (cmd
->without_daemon
) {
6306 if (options
.pnn
!= -1) {
6308 "Cannot specify node for command %s\n",
6313 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6314 talloc_free(tmp_ctx
);
6318 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6320 fprintf(stderr
, "Memory allocation error\n");
6324 ctdb
->ev
= tevent_context_init(ctdb
);
6325 if (ctdb
->ev
== NULL
) {
6326 fprintf(stderr
, "Failed to initialize tevent\n");
6330 ctdb_socket
= path_socket(ctdb
, "ctdbd");
6331 if (ctdb_socket
== NULL
) {
6332 fprintf(stderr
, "Memory allocation error\n");
6336 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6338 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6341 if (!find_node_xpnn(ctdb
, NULL
)) {
6342 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6347 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6348 srvid_offset
= getpid() & 0xFFFF;
6349 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6351 if (options
.pnn
!= -1) {
6352 status
= verify_pnn(ctdb
, options
.pnn
);
6357 ctdb
->cmd_pnn
= options
.pnn
;
6359 ctdb
->cmd_pnn
= ctdb
->pnn
;
6362 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6363 fprintf(stderr
, "Node cannot be specified for command %s\n",
6368 ctdb
->leader_pnn
= CTDB_UNKNOWN_PNN
;
6369 ret
= ctdb_client_set_message_handler(ctdb
->ev
,
6375 fprintf(stderr
, "Failed to setup leader handler\n");
6379 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6380 talloc_free(tmp_ctx
);
6384 talloc_free(tmp_ctx
);
6388 static void signal_handler(int sig
)
6390 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6393 static void alarm_handler(int sig
)
6395 /* Kill any child processes */
6396 signal(SIGTERM
, signal_handler
);
6402 int main(int argc
, const char *argv
[])
6405 const char **extra_argv
;
6407 const struct ctdb_cmd
*cmd
;
6408 const char *test_mode
;
6415 /* Set default options */
6416 options
.debuglevelstr
= NULL
;
6417 options
.timelimit
= 10;
6419 options
.maxruntime
= 0;
6422 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6423 POPT_CONTEXT_KEEP_FIRST
);
6424 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6425 fprintf(stderr
, "Invalid option %s: %s\n",
6426 poptBadOption(pc
, 0), poptStrerror(opt
));
6430 if (options
.maxruntime
== 0) {
6431 const char *ctdb_timeout
;
6433 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6434 if (ctdb_timeout
!= NULL
) {
6435 options
.maxruntime
= smb_strtoul(ctdb_timeout
,
6441 fprintf(stderr
, "Invalid value CTDB_TIMEOUT\n");
6445 options
.maxruntime
= 120;
6449 if (options
.machineparsable
) {
6450 options
.machinereadable
= 1;
6453 /* setup the remaining options for the commands */
6455 extra_argv
= poptGetArgs(pc
);
6458 while (extra_argv
[extra_argc
]) extra_argc
++;
6461 if (extra_argc
< 1) {
6465 cmd
= match_command(extra_argv
[0]);
6467 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6471 /* Enable logging */
6472 setup_logging("ctdb", DEBUG_STDERR
);
6473 ok
= debug_level_parse(options
.debuglevelstr
, &loglevel
);
6475 loglevel
= DEBUG_ERR
;
6477 debuglevel_set(loglevel
);
6479 /* Stop process group kill in alarm_handler() from killing tests */
6480 test_mode
= getenv("CTDB_TEST_MODE");
6481 if (test_mode
!= NULL
) {
6482 const char *have_setpgid
= getenv("CTDB_TOOL_SETPGID");
6483 if (have_setpgid
== NULL
) {
6485 setenv("CTDB_TOOL_SETPGID", "1", 1);
6489 signal(SIGALRM
, alarm_handler
);
6490 alarm(options
.maxruntime
);
6492 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6497 (void)poptFreeContext(pc
);