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)
56 const char *debuglevelstr
;
64 int printemptyrecords
;
71 static poptContext pc
;
74 struct tevent_context
*ev
;
75 struct ctdb_client_context
*client
;
76 struct ctdb_node_map
*nodemap
;
77 uint32_t pnn
, cmd_pnn
, leader_pnn
;
81 static void usage(const char *command
);
87 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
89 return (tv2
->tv_sec
- tv
->tv_sec
) +
90 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
93 static struct ctdb_node_and_flags
*get_node_by_pnn(
94 struct ctdb_node_map
*nodemap
,
99 for (i
=0; i
<nodemap
->num
; i
++) {
100 if (nodemap
->node
[i
].pnn
== pnn
) {
101 return &nodemap
->node
[i
];
107 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
109 static const struct {
113 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
114 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
115 { NODE_FLAGS_BANNED
, "BANNED" },
116 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
117 { NODE_FLAGS_DELETED
, "DELETED" },
118 { NODE_FLAGS_STOPPED
, "STOPPED" },
119 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
121 char *flags_str
= NULL
;
124 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
125 if (flags
& flag_names
[i
].flag
) {
126 if (flags_str
== NULL
) {
127 flags_str
= talloc_asprintf(mem_ctx
,
128 "%s", flag_names
[i
].name
);
130 flags_str
= talloc_asprintf_append(flags_str
,
131 "|%s", flag_names
[i
].name
);
133 if (flags_str
== NULL
) {
134 return "OUT-OF-MEMORY";
138 if (flags_str
== NULL
) {
145 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
152 * Get consistent nodemap information.
154 * If nodemap is already cached, use that. If not get it.
155 * If the current node is BANNED, then get nodemap from "better" node.
157 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
160 struct ctdb_node_map
*nodemap
;
161 struct ctdb_node_and_flags
*node
;
162 uint32_t current_node
;
166 TALLOC_FREE(ctdb
->nodemap
);
169 if (ctdb
->nodemap
!= NULL
) {
170 return ctdb
->nodemap
;
173 tmp_ctx
= talloc_new(ctdb
);
174 if (tmp_ctx
== NULL
) {
178 current_node
= ctdb
->pnn
;
180 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
181 current_node
, TIMEOUT(), &nodemap
);
183 fprintf(stderr
, "Failed to get nodemap from node %u\n",
188 node
= get_node_by_pnn(nodemap
, current_node
);
189 if (node
->flags
& NODE_FLAGS_BANNED
) {
192 current_node
= (current_node
+ 1) % nodemap
->num
;
193 node
= get_node_by_pnn(nodemap
, current_node
);
195 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
198 } while (current_node
!= ctdb
->pnn
);
200 if (current_node
== ctdb
->pnn
) {
201 /* Tried all nodes in the cluster */
202 fprintf(stderr
, "Warning: All nodes are banned.\n");
209 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
213 talloc_free(tmp_ctx
);
217 static void print_pnn(uint32_t pnn
)
219 if (pnn
== CTDB_UNKNOWN_PNN
) {
227 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
229 struct ctdb_node_map
*nodemap
;
237 nodemap
= get_nodemap(ctdb
, false);
238 if (nodemap
== NULL
) {
243 for (i
=0; i
<nodemap
->num
; i
++) {
244 if (nodemap
->node
[i
].pnn
== (uint32_t)pnn
) {
250 fprintf(stderr
, "Node %u does not exist\n", pnn
);
254 if (nodemap
->node
[i
].flags
&
255 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
256 fprintf(stderr
, "Node %u has status %s\n", pnn
,
257 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
264 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
265 struct ctdb_node_map
*nodemap
)
267 struct ctdb_node_map
*nodemap2
;
269 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
270 if (nodemap2
== NULL
) {
274 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
276 if (nodemap2
->node
== NULL
) {
277 talloc_free(nodemap2
);
285 * Get the number and the list of matching nodes
287 * nodestring := NULL | all | pnn,[pnn,...]
289 * If nodestring is NULL, use the current node.
291 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
292 const char *nodestring
,
293 struct ctdb_node_map
**out
)
295 struct ctdb_node_map
*nodemap
, *nodemap2
;
296 struct ctdb_node_and_flags
*node
;
299 nodemap
= get_nodemap(ctdb
, false);
300 if (nodemap
== NULL
) {
304 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
305 if (nodemap2
== NULL
) {
309 if (nodestring
== NULL
) {
310 for (i
=0; i
<nodemap
->num
; i
++) {
311 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
312 nodemap2
->node
[0] = nodemap
->node
[i
];
321 if (strcmp(nodestring
, "all") == 0) {
322 for (i
=0; i
<nodemap
->num
; i
++) {
323 nodemap2
->node
[i
] = nodemap
->node
[i
];
325 nodemap2
->num
= nodemap
->num
;
332 ns
= talloc_strdup(mem_ctx
, nodestring
);
337 tok
= strtok(ns
, ",");
338 while (tok
!= NULL
) {
341 pnn
= (uint32_t)smb_strtoul(tok
,
347 fprintf(stderr
, "Invalid node %s\n", tok
);
351 node
= get_node_by_pnn(nodemap
, pnn
);
353 fprintf(stderr
, "Node %u does not exist\n",
358 nodemap2
->node
[nodemap2
->num
] = *node
;
361 tok
= strtok(NULL
, ",");
370 /* Compare IP address */
371 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
375 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
379 switch (ip1
->sa
.sa_family
) {
381 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
382 sizeof(struct in_addr
)) == 0);
386 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
387 sizeof(struct in6_addr
)) == 0);
394 /* Append a node to a node map with given address and flags */
395 static bool node_map_add(struct ctdb_node_map
*nodemap
,
396 const char *nstr
, uint32_t flags
)
400 struct ctdb_node_and_flags
*n
;
403 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
405 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
410 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
411 struct ctdb_node_and_flags
, num
+1);
412 if (nodemap
->node
== NULL
) {
416 n
= &nodemap
->node
[num
];
421 nodemap
->num
= num
+1;
425 /* Read a nodes file into a node map */
426 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
432 struct ctdb_node_map
*nodemap
;
434 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
435 if (nodemap
== NULL
) {
439 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
444 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
448 for (i
=0; i
<nlines
; i
++) {
454 /* strip leading spaces */
455 while((*node
== ' ') || (*node
== '\t')) {
461 /* strip trailing spaces */
463 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
473 /* A "deleted" node is a node that is
474 commented out in the nodes file. This is
475 used instead of removing a line, which
476 would cause subsequent nodes to change
478 flags
= NODE_FLAGS_DELETED
;
479 node
= discard_const("0.0.0.0");
483 if (! node_map_add(nodemap
, node
, flags
)) {
485 TALLOC_FREE(nodemap
);
494 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
496 struct ctdb_node_map
*nodemap
;
497 const char *nodes_list
= NULL
;
499 const char *basedir
= getenv("CTDB_BASE");
500 if (basedir
== NULL
) {
501 basedir
= CTDB_ETCDIR
;
503 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
504 if (nodes_list
== NULL
) {
505 fprintf(stderr
, "Memory allocation error\n");
509 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
510 if (nodemap
== NULL
) {
511 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
519 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
520 struct ctdb_context
*ctdb
,
521 struct ctdb_dbid_map
*dbmap
,
524 struct ctdb_dbid
*db
= NULL
;
529 for (i
=0; i
<dbmap
->num
; i
++) {
530 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
531 ctdb
->pnn
, TIMEOUT(),
532 dbmap
->dbs
[i
].db_id
, &name
);
537 if (strcmp(db_name
, name
) == 0) {
538 talloc_free(discard_const(name
));
547 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
548 const char *db_arg
, uint32_t *db_id
,
549 const char **db_name
, uint8_t *db_flags
)
551 struct ctdb_dbid_map
*dbmap
;
552 struct ctdb_dbid
*db
= NULL
;
554 const char *name
= NULL
;
558 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
559 ctdb
->pnn
, TIMEOUT(), &dbmap
);
564 if (strncmp(db_arg
, "0x", 2) == 0) {
565 id
= smb_strtoul(db_arg
, NULL
, 0, &ret
, SMB_STR_STANDARD
);
569 for (i
=0; i
<dbmap
->num
; i
++) {
570 if (id
== dbmap
->dbs
[i
].db_id
) {
577 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
581 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
586 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
587 ctdb
->pnn
, TIMEOUT(), id
, &name
);
596 if (db_name
!= NULL
) {
597 *db_name
= talloc_strdup(mem_ctx
, name
);
599 if (db_flags
!= NULL
) {
600 *db_flags
= db
->flags
;
605 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
612 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
617 data
.dsize
= len
/ 2;
618 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
619 if (data
.dptr
== NULL
) {
623 for (i
=0; i
<data
.dsize
; i
++) {
624 bool ok
= hex_byte(&str
[i
*2], &data
.dptr
[i
]);
626 fprintf(stderr
, "Invalid hex: %s\n", &str
[i
*2]);
635 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
641 if (strncmp(str
, "0x", 2) == 0) {
642 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
647 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
648 if (data
.dptr
== NULL
) {
658 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
659 const char *path
, int argc
, const char **argv
)
662 int save_errno
, status
, ret
;
663 const char **new_argv
;
666 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
667 if (new_argv
== NULL
) {
672 for (i
=0; i
<argc
; i
++) {
673 new_argv
[i
+1] = argv
[i
];
675 new_argv
[argc
+1] = NULL
;
680 talloc_free(new_argv
);
681 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
682 command
, path
, strerror(save_errno
));
687 ret
= execv(path
, discard_const(new_argv
));
691 /* Should not happen */
695 talloc_free(new_argv
);
697 ret
= waitpid(pid
, &status
, 0);
700 fprintf(stderr
, "waitpid() failed for %s - %s\n",
701 command
, strerror(save_errno
));
705 if (WIFEXITED(status
)) {
706 int pstatus
= WEXITSTATUS(status
);
707 if (WIFSIGNALED(status
)) {
708 fprintf(stderr
, "%s terminated with signal %d\n",
709 command
, WTERMSIG(status
));
711 } else if (pstatus
>= 64 && pstatus
< 255) {
712 fprintf(stderr
, "%s failed with error %d\n",
713 command
, pstatus
-64);
719 } else if (WIFSIGNALED(status
)) {
720 fprintf(stderr
, "%s terminated with signal %d\n",
721 command
, WTERMSIG(status
));
728 static void leader_handler(uint64_t srvid
,
732 struct ctdb_context
*ctdb
= talloc_get_type_abort(
733 private_data
, struct ctdb_context
);
738 ret
= ctdb_uint32_pull(data
.dptr
, data
.dsize
, &leader_pnn
, &np
);
744 ctdb
->leader_pnn
= leader_pnn
;
751 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
752 int argc
, const char **argv
)
754 printf("%s\n", SAMBA_VERSION_STRING
);
758 static bool partially_online(TALLOC_CTX
*mem_ctx
,
759 struct ctdb_context
*ctdb
,
760 struct ctdb_node_and_flags
*node
)
762 struct ctdb_iface_list
*iface_list
;
767 if (node
->flags
!= 0) {
771 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
772 node
->pnn
, TIMEOUT(), &iface_list
);
778 for (i
=0; i
< iface_list
->num
; i
++) {
779 if (iface_list
->iface
[i
].link_state
== 0) {
788 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
789 struct ctdb_context
*ctdb
,
790 struct ctdb_node_map
*nodemap
,
793 struct ctdb_node_and_flags
*node
;
796 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
800 "Disconnected", options
.sep
,
801 "Banned", options
.sep
,
802 "Disabled", options
.sep
,
803 "Unhealthy", options
.sep
,
804 "Stopped", options
.sep
,
805 "Inactive", options
.sep
,
806 "PartiallyOnline", options
.sep
,
807 "ThisNode", options
.sep
);
809 for (i
=0; i
<nodemap
->num
; i
++) {
810 node
= &nodemap
->node
[i
];
811 if (node
->flags
& NODE_FLAGS_DELETED
) {
815 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
817 node
->pnn
, options
.sep
,
818 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
820 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
821 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
822 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
824 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
825 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
826 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
827 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
828 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
833 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
834 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
837 struct ctdb_node_and_flags
*node
;
838 int num_deleted_nodes
= 0;
841 for (i
=0; i
<nodemap
->num
; i
++) {
842 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
848 if (num_deleted_nodes
== 0) {
849 printf("Number of nodes:%d\n", nodemap
->num
);
851 printf("Number of nodes:%d "
852 "(including %d deleted nodes)\n",
853 nodemap
->num
, num_deleted_nodes
);
857 for (i
=0; i
<nodemap
->num
; i
++) {
858 node
= &nodemap
->node
[i
];
859 if (node
->flags
& NODE_FLAGS_DELETED
) {
863 printf("pnn:%u %-16s %s%s\n",
865 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
866 partially_online(mem_ctx
, ctdb
, node
) ?
868 pretty_print_flags(mem_ctx
, node
->flags
),
869 node
->pnn
== mypnn
? " (THIS NODE)" : "");
873 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
874 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
875 struct ctdb_vnn_map
*vnnmap
, int recmode
,
880 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
882 if (vnnmap
->generation
== INVALID_GENERATION
) {
883 printf("Generation:INVALID\n");
885 printf("Generation:%u\n", vnnmap
->generation
);
887 printf("Size:%d\n", vnnmap
->size
);
888 for (i
=0; i
<vnnmap
->size
; i
++) {
889 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
892 printf("Recovery mode:%s (%d)\n",
893 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
895 printf("Recovery master:");
896 print_pnn(recmaster
);
899 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
900 int argc
, const char **argv
)
902 struct ctdb_node_map
*nodemap
;
903 struct ctdb_vnn_map
*vnnmap
;
912 nodemap
= get_nodemap(ctdb
, false);
913 if (nodemap
== NULL
) {
917 if (options
.machinereadable
== 1) {
918 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
922 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
923 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
928 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
929 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
934 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
935 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
940 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
945 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
946 int argc
, const char **argv
)
948 struct ctdb_uptime
*uptime
;
949 int ret
, tmp
, days
, hours
, minutes
, seconds
;
951 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
952 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
957 printf("Current time of node %-4u : %s",
958 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
960 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
961 seconds
= tmp
% 60; tmp
/= 60;
962 minutes
= tmp
% 60; tmp
/= 60;
963 hours
= tmp
% 24; tmp
/= 24;
966 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
967 days
, hours
, minutes
, seconds
,
968 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
970 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
971 seconds
= tmp
% 60; tmp
/= 60;
972 minutes
= tmp
% 60; tmp
/= 60;
973 hours
= tmp
% 24; tmp
/= 24;
976 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
977 days
, hours
, minutes
, seconds
,
978 ctime(&uptime
->last_recovery_finished
.tv_sec
));
980 printf("Duration of last recovery/failover: %lf seconds\n",
981 timeval_delta(&uptime
->last_recovery_finished
,
982 &uptime
->last_recovery_started
));
987 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
988 int argc
, const char **argv
)
991 int ret
, num_clients
;
993 tv
= timeval_current();
994 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
995 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
1000 printf("response from %u time=%.6f sec (%d clients)\n",
1001 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
1005 const char *runstate_to_string(enum ctdb_runstate runstate
);
1006 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
1008 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1009 int argc
, const char **argv
)
1011 enum ctdb_runstate runstate
;
1015 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1016 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
1022 for (i
=0; i
<argc
; i
++) {
1023 enum ctdb_runstate t
;
1026 t
= ctdb_runstate_from_string(argv
[i
]);
1027 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
1028 printf("Invalid run state (%s)\n", argv
[i
]);
1032 if (t
== runstate
) {
1039 printf("CTDB not in required run state (got %s)\n",
1040 ctdb_runstate_to_string(runstate
));
1044 printf("%s\n", ctdb_runstate_to_string(runstate
));
1048 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1049 int argc
, const char **argv
)
1051 struct ctdb_var_list
*tun_var_list
;
1060 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1061 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1064 "Failed to get list of variables from node %u\n",
1070 for (i
=0; i
<tun_var_list
->count
; i
++) {
1071 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1078 printf("No such tunable %s\n", argv
[0]);
1082 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1083 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1088 printf("%-26s = %u\n", argv
[0], value
);
1092 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1093 int argc
, const char **argv
)
1095 struct ctdb_var_list
*tun_var_list
;
1096 struct ctdb_tunable tunable
;
1105 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1106 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1109 "Failed to get list of variables from node %u\n",
1115 for (i
=0; i
<tun_var_list
->count
; i
++) {
1116 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1123 printf("No such tunable %s\n", argv
[0]);
1127 tunable
.name
= argv
[0];
1128 tunable
.value
= smb_strtoul(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1133 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1134 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1138 "Setting obsolete tunable variable '%s'\n",
1147 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1148 int argc
, const char **argv
)
1150 struct ctdb_var_list
*tun_var_list
;
1157 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1158 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1163 for (i
=0; i
<tun_var_list
->count
; i
++) {
1164 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1173 } stats_fields
[] = {
1174 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1175 STATISTICS_FIELD(num_clients
),
1176 STATISTICS_FIELD(frozen
),
1177 STATISTICS_FIELD(recovering
),
1178 STATISTICS_FIELD(num_recoveries
),
1179 STATISTICS_FIELD(client_packets_sent
),
1180 STATISTICS_FIELD(client_packets_recv
),
1181 STATISTICS_FIELD(node_packets_sent
),
1182 STATISTICS_FIELD(node_packets_recv
),
1183 STATISTICS_FIELD(keepalive_packets_sent
),
1184 STATISTICS_FIELD(keepalive_packets_recv
),
1185 STATISTICS_FIELD(node
.req_call
),
1186 STATISTICS_FIELD(node
.reply_call
),
1187 STATISTICS_FIELD(node
.req_dmaster
),
1188 STATISTICS_FIELD(node
.reply_dmaster
),
1189 STATISTICS_FIELD(node
.reply_error
),
1190 STATISTICS_FIELD(node
.req_message
),
1191 STATISTICS_FIELD(node
.req_control
),
1192 STATISTICS_FIELD(node
.reply_control
),
1193 STATISTICS_FIELD(node
.req_tunnel
),
1194 STATISTICS_FIELD(client
.req_call
),
1195 STATISTICS_FIELD(client
.req_message
),
1196 STATISTICS_FIELD(client
.req_control
),
1197 STATISTICS_FIELD(client
.req_tunnel
),
1198 STATISTICS_FIELD(timeouts
.call
),
1199 STATISTICS_FIELD(timeouts
.control
),
1200 STATISTICS_FIELD(timeouts
.traverse
),
1201 STATISTICS_FIELD(locks
.num_calls
),
1202 STATISTICS_FIELD(locks
.num_current
),
1203 STATISTICS_FIELD(locks
.num_pending
),
1204 STATISTICS_FIELD(locks
.num_failed
),
1205 STATISTICS_FIELD(total_calls
),
1206 STATISTICS_FIELD(pending_calls
),
1207 STATISTICS_FIELD(childwrite_calls
),
1208 STATISTICS_FIELD(pending_childwrite_calls
),
1209 STATISTICS_FIELD(memory_used
),
1210 STATISTICS_FIELD(max_hop_count
),
1211 STATISTICS_FIELD(total_ro_delegations
),
1212 STATISTICS_FIELD(total_ro_revokes
),
1215 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1217 static void print_statistics_machine(struct ctdb_statistics
*s
,
1223 printf("CTDB version%s", options
.sep
);
1224 printf("Current time of statistics%s", options
.sep
);
1225 printf("Statistics collected since%s", options
.sep
);
1226 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1227 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1229 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1230 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1231 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1232 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1234 printf("num_reclock_recd_latency%s", options
.sep
);
1235 printf("min_reclock_recd_latency%s", options
.sep
);
1236 printf("avg_reclock_recd_latency%s", options
.sep
);
1237 printf("max_reclock_recd_latency%s", options
.sep
);
1239 printf("num_call_latency%s", options
.sep
);
1240 printf("min_call_latency%s", options
.sep
);
1241 printf("avg_call_latency%s", options
.sep
);
1242 printf("max_call_latency%s", options
.sep
);
1244 printf("num_lockwait_latency%s", options
.sep
);
1245 printf("min_lockwait_latency%s", options
.sep
);
1246 printf("avg_lockwait_latency%s", options
.sep
);
1247 printf("max_lockwait_latency%s", options
.sep
);
1249 printf("num_childwrite_latency%s", options
.sep
);
1250 printf("min_childwrite_latency%s", options
.sep
);
1251 printf("avg_childwrite_latency%s", options
.sep
);
1252 printf("max_childwrite_latency%s", options
.sep
);
1256 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1257 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1258 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1259 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1261 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1264 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1265 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1266 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1267 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1269 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1270 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1271 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1272 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1274 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1275 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1276 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1277 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1279 printf("%u%s", s
->locks
.latency
.num
, options
.sep
);
1280 printf("%.6f%s", s
->locks
.latency
.min
, options
.sep
);
1281 printf("%.6f%s", LATENCY_AVG(s
->locks
.latency
), options
.sep
);
1282 printf("%.6f%s", s
->locks
.latency
.max
, options
.sep
);
1284 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1285 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1286 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1287 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1291 static void print_statistics(struct ctdb_statistics
*s
)
1293 int tmp
, days
, hours
, minutes
, seconds
;
1295 const char *prefix
= NULL
;
1298 tmp
= s
->statistics_current_time
.tv_sec
-
1299 s
->statistics_start_time
.tv_sec
;
1300 seconds
= tmp
% 60; tmp
/= 60;
1301 minutes
= tmp
% 60; tmp
/= 60;
1302 hours
= tmp
% 24; tmp
/= 24;
1305 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1306 printf("Current time of statistics : %s",
1307 ctime(&s
->statistics_current_time
.tv_sec
));
1308 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1309 days
, hours
, minutes
, seconds
,
1310 ctime(&s
->statistics_start_time
.tv_sec
));
1312 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1313 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1314 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1316 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1317 prefix
= stats_fields
[i
].name
;
1318 printf(" %*.*s\n", preflen
-1, preflen
-1,
1319 stats_fields
[i
].name
);
1324 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1325 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1326 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1329 printf(" hop_count_buckets:");
1330 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1331 printf(" %d", s
->hop_count_bucket
[i
]);
1334 printf(" lock_buckets:");
1335 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1336 printf(" %d", s
->locks
.buckets
[i
]);
1339 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1340 "locks_latency MIN/AVG/MAX",
1341 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1342 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1344 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1345 "reclock_ctdbd MIN/AVG/MAX",
1346 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1347 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1349 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1350 "reclock_recd MIN/AVG/MAX",
1351 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1352 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1354 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1355 "call_latency MIN/AVG/MAX",
1356 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1357 s
->call_latency
.max
, s
->call_latency
.num
);
1359 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1360 "childwrite_latency MIN/AVG/MAX",
1361 s
->childwrite_latency
.min
,
1362 LATENCY_AVG(s
->childwrite_latency
),
1363 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1366 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1367 int argc
, const char **argv
)
1369 struct ctdb_statistics
*stats
;
1373 usage("statistics");
1376 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1377 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1382 if (options
.machinereadable
) {
1383 print_statistics_machine(stats
, true);
1385 print_statistics(stats
);
1391 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1392 struct ctdb_context
*ctdb
,
1393 int argc
, const char **argv
)
1398 usage("statisticsreset");
1401 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1402 ctdb
->cmd_pnn
, TIMEOUT());
1410 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1411 int argc
, const char **argv
)
1413 struct ctdb_statistics_list
*slist
;
1414 int ret
, count
= 0, i
;
1415 bool show_header
= true;
1422 count
= atoi(argv
[0]);
1425 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1426 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1431 for (i
=0; i
<slist
->num
; i
++) {
1432 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1435 if (options
.machinereadable
== 1) {
1436 print_statistics_machine(&slist
->stats
[i
],
1438 show_header
= false;
1440 print_statistics(&slist
->stats
[i
]);
1442 if (count
> 0 && i
== count
) {
1450 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1452 const struct ctdb_public_ip
*ip_a
= a
;
1453 const struct ctdb_public_ip
*ip_b
= b
;
1455 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1458 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1459 struct ctdb_public_ip_list
*ips
,
1460 struct ctdb_public_ip_info
**ipinfo
,
1464 char *conf
, *avail
, *active
;
1466 if (options
.machinereadable
== 1) {
1467 printf("%s%s%s%s%s", options
.sep
,
1468 "Public IP", options
.sep
,
1469 "Node", options
.sep
);
1470 if (options
.verbose
== 1) {
1471 printf("%s%s%s%s%s%s\n",
1472 "ActiveInterfaces", options
.sep
,
1473 "AvailableInterfaces", options
.sep
,
1474 "ConfiguredInterfaces", options
.sep
);
1480 printf("Public IPs on ALL nodes\n");
1482 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1486 for (i
= 0; i
< ips
->num
; i
++) {
1488 if (options
.machinereadable
== 1) {
1489 printf("%s%s%s%d%s", options
.sep
,
1490 ctdb_sock_addr_to_string(
1491 mem_ctx
, &ips
->ip
[i
].addr
, false),
1493 (int)ips
->ip
[i
].pnn
, options
.sep
);
1495 printf("%s", ctdb_sock_addr_to_string(
1496 mem_ctx
, &ips
->ip
[i
].addr
, false));
1499 if (options
.verbose
== 0) {
1500 if (options
.machinereadable
== 1) {
1503 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1512 if (ipinfo
[i
] == NULL
) {
1516 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1517 struct ctdb_iface
*iface
;
1519 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1521 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1523 conf
= talloc_asprintf_append(
1524 conf
, ",%s", iface
->name
);
1527 if (ipinfo
[i
]->active_idx
== j
) {
1528 active
= iface
->name
;
1531 if (iface
->link_state
== 0) {
1535 if (avail
== NULL
) {
1536 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1538 avail
= talloc_asprintf_append(
1539 avail
, ",%s", iface
->name
);
1545 if (options
.machinereadable
== 1) {
1546 printf("%s%s%s%s%s%s\n",
1547 active
? active
: "", options
.sep
,
1548 avail
? avail
: "", options
.sep
,
1549 conf
? conf
: "", options
.sep
);
1551 printf(" node[%d] active[%s] available[%s]"
1552 " configured[%s]\n",
1553 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1554 avail
? avail
: "", conf
? conf
: "");
1559 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1560 size_t datalen
, void *private_data
)
1562 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1563 private_data
, struct ctdb_public_ip_list
);
1564 struct ctdb_public_ip
*ip
;
1566 ip
= (struct ctdb_public_ip
*)databuf
;
1567 ips
->ip
[ips
->num
] = *ip
;
1573 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1574 struct ctdb_public_ip_list
**out
)
1576 struct ctdb_node_map
*nodemap
;
1577 struct ctdb_public_ip_list
*ips
;
1578 struct db_hash_context
*ipdb
;
1583 nodemap
= get_nodemap(ctdb
, false);
1584 if (nodemap
== NULL
) {
1588 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1593 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1599 for (i
=0; i
<count
; i
++) {
1600 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1601 pnn_list
[i
], TIMEOUT(),
1607 for (j
=0; j
<ips
->num
; j
++) {
1608 struct ctdb_public_ip ip
;
1610 ip
.pnn
= ips
->ip
[j
].pnn
;
1611 ip
.addr
= ips
->ip
[j
].addr
;
1613 if (pnn_list
[i
] == ip
.pnn
) {
1614 /* Node claims IP is hosted on it, so
1615 * save that information
1617 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1619 (uint8_t *)&ip
, sizeof(ip
));
1624 /* Node thinks IP is hosted elsewhere,
1625 * so overwrite with CTDB_UNKNOWN_PNN
1626 * if there's no existing entry
1628 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1630 if (ret
== ENOENT
) {
1631 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1632 ret
= db_hash_add(ipdb
,
1633 (uint8_t *)&ip
.addr
,
1647 talloc_free(pnn_list
);
1649 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1654 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1659 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1660 if (ips
->ip
== NULL
) {
1664 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1669 if ((unsigned int)count
!= ips
->num
) {
1683 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1684 int argc
, const char **argv
)
1686 struct ctdb_public_ip_list
*ips
;
1687 struct ctdb_public_ip_info
**ipinfo
;
1690 bool do_all
= false;
1697 if (strcmp(argv
[0], "all") == 0) {
1705 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1707 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1708 ctdb
->cmd_pnn
, TIMEOUT(),
1715 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1716 ctdb_public_ip_cmp
);
1718 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1719 if (ipinfo
== NULL
) {
1723 for (i
=0; i
<ips
->num
; i
++) {
1726 pnn
= ips
->ip
[i
].pnn
;
1728 pnn
= ctdb
->cmd_pnn
;
1730 if (pnn
== CTDB_UNKNOWN_PNN
) {
1734 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1736 TIMEOUT(), &ips
->ip
[i
].addr
,
1743 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1747 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1748 int argc
, const char **argv
)
1750 struct ctdb_public_ip_info
*ipinfo
;
1751 ctdb_sock_addr addr
;
1759 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1761 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1765 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1766 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1770 printf("Node %u does not know about IP %s\n",
1771 ctdb
->cmd_pnn
, argv
[0]);
1776 printf("Public IP[%s] info on node %u\n",
1777 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1780 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1781 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1782 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1784 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1785 struct ctdb_iface
*iface
;
1787 iface
= &ipinfo
->ifaces
->iface
[i
];
1788 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1789 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1791 iface
->link_state
== 0 ? "down" : "up",
1793 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1799 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1800 int argc
, const char **argv
)
1802 struct ctdb_iface_list
*ifaces
;
1810 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1811 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1816 if (ifaces
->num
== 0) {
1817 printf("No interfaces configured on node %u\n",
1822 if (options
.machinereadable
) {
1823 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1824 "Name", options
.sep
,
1825 "LinkStatus", options
.sep
,
1826 "References", options
.sep
);
1828 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1831 for (i
=0; i
<ifaces
->num
; i
++) {
1832 if (options
.machinereadable
) {
1833 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1834 ifaces
->iface
[i
].name
, options
.sep
,
1835 ifaces
->iface
[i
].link_state
, options
.sep
,
1836 ifaces
->iface
[i
].references
, options
.sep
);
1838 printf("name:%s link:%s references:%u\n",
1839 ifaces
->iface
[i
].name
,
1840 ifaces
->iface
[i
].link_state
? "up" : "down",
1841 ifaces
->iface
[i
].references
);
1848 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1849 int argc
, const char **argv
)
1851 struct ctdb_iface_list
*ifaces
;
1852 struct ctdb_iface
*iface
;
1857 usage("setifacelink");
1860 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1861 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1865 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1866 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1869 "Failed to get interface information from node %u\n",
1875 for (i
=0; i
<ifaces
->num
; i
++) {
1876 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1877 iface
= &ifaces
->iface
[i
];
1882 if (iface
== NULL
) {
1883 printf("Interface %s not configured on node %u\n",
1884 argv
[0], ctdb
->cmd_pnn
);
1888 if (strcmp(argv
[1], "up") == 0) {
1889 iface
->link_state
= 1;
1890 } else if (strcmp(argv
[1], "down") == 0) {
1891 iface
->link_state
= 0;
1893 usage("setifacelink");
1897 iface
->references
= 0;
1899 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1900 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1908 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1909 struct ctdb_context
*ctdb
,
1910 int argc
, const char **argv
)
1917 if (argc
!= 1 && argc
!= 2) {
1918 usage("process-exists");
1921 pid
= atoi(argv
[0]);
1923 srvid
= smb_strtoull(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1930 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1931 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1933 struct ctdb_pid_srvid pid_srvid
;
1935 pid_srvid
.pid
= pid
;
1936 pid_srvid
.srvid
= srvid
;
1938 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
1939 ctdb
->client
, ctdb
->cmd_pnn
,
1940 TIMEOUT(), &pid_srvid
,
1949 printf("PID %d %s\n", pid
,
1950 (status
== 0 ? "exists" : "does not exist"));
1952 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
1953 (status
== 0 ? "exists" : "does not exist"));
1958 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1959 int argc
, const char **argv
)
1961 struct ctdb_dbid_map
*dbmap
;
1969 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1970 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1975 if (options
.machinereadable
== 1) {
1976 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1979 "Name", options
.sep
,
1980 "Path", options
.sep
,
1981 "Persistent", options
.sep
,
1982 "Sticky", options
.sep
,
1983 "Unhealthy", options
.sep
,
1984 "Readonly", options
.sep
,
1985 "Replicated", options
.sep
);
1987 printf("Number of databases:%d\n", dbmap
->num
);
1990 for (i
=0; i
<dbmap
->num
; i
++) {
2000 db_id
= dbmap
->dbs
[i
].db_id
;
2002 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2003 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2009 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2010 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2016 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2017 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2023 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
2024 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
2025 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
2026 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
2028 if (options
.machinereadable
== 1) {
2029 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2034 !! (persistent
), options
.sep
,
2035 !! (sticky
), options
.sep
,
2036 !! (health
), options
.sep
,
2037 !! (readonly
), options
.sep
,
2038 !! (replicated
), options
.sep
);
2040 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2042 persistent
? " PERSISTENT" : "",
2043 sticky
? " STICKY" : "",
2044 readonly
? " READONLY" : "",
2045 replicated
? " REPLICATED" : "",
2046 health
? " UNHEALTHY" : "");
2049 talloc_free(discard_const(name
));
2050 talloc_free(discard_const(path
));
2051 talloc_free(discard_const(health
));
2057 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2058 int argc
, const char **argv
)
2061 const char *db_name
, *db_path
, *db_health
;
2066 usage("getdbstatus");
2069 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2073 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2074 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2080 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2081 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2087 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2088 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2089 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2090 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2091 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2092 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2093 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2097 struct dump_record_state
{
2101 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2103 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2107 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2108 for (i
=0; i
<val
.dsize
; i
++) {
2109 if (ISASCII(val
.dptr
[i
])) {
2110 fprintf(stdout
, "%c", val
.dptr
[i
]);
2112 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2115 fprintf(stdout
, "\"\n");
2118 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2120 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2121 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2122 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2123 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2124 fprintf(stdout
, " MIGRATED_WITH_DATA");
2126 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2127 fprintf(stdout
, " VACUUM_MIGRATED");
2129 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2130 fprintf(stdout
, " AUTOMATIC");
2132 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2133 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2135 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2136 fprintf(stdout
, " RO_HAVE_READONLY");
2138 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2139 fprintf(stdout
, " RO_REVOKING_READONLY");
2141 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2142 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2144 fprintf(stdout
, "\n");
2148 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2149 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2151 struct dump_record_state
*state
=
2152 (struct dump_record_state
*)private_data
;
2156 dump_tdb_data("key", key
);
2157 dump_ltdb_header(header
);
2158 dump_tdb_data("data", data
);
2159 fprintf(stdout
, "\n");
2164 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2165 int argc
, const char **argv
)
2167 struct ctdb_db_context
*db
;
2168 const char *db_name
;
2171 struct dump_record_state state
;
2178 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2182 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2185 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2191 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2192 ctdb
->cmd_pnn
, TIMEOUT(),
2193 dump_record
, &state
);
2195 printf("Dumped %u records\n", state
.count
);
2200 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2201 int argc
, const char **argv
)
2203 struct ctdb_db_context
*db
;
2204 const char *db_name
;
2207 struct dump_record_state state
;
2214 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2218 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2221 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2226 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2228 printf("Dumped %u record(s)\n", state
.count
);
2233 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2234 struct ctdb_context
*ctdb
,
2235 int argc
, const char **argv
)
2241 usage("getcapabilities");
2244 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2245 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2250 if (options
.machinereadable
== 1) {
2251 printf("%s%s%s%s%s\n",
2253 "RECMASTER", options
.sep
,
2254 "LMASTER", options
.sep
);
2255 printf("%s%d%s%d%s\n", options
.sep
,
2256 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2257 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2259 printf("RECMASTER: %s\n",
2260 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2261 printf("LMASTER: %s\n",
2262 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2268 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2269 int argc
, const char **argv
)
2271 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2275 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2276 int argc
, const char **argv
)
2278 char *t
, *lvs_helper
= NULL
;
2284 t
= getenv("CTDB_LVS_HELPER");
2286 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2288 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2289 CTDB_HELPER_BINDIR
);
2292 if (lvs_helper
== NULL
) {
2293 fprintf(stderr
, "Unable to set LVS helper\n");
2297 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2300 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2301 int argc
, const char **argv
)
2311 found
= debug_level_parse(argv
[0], &log_level
);
2314 "Invalid debug level '%s'. Valid levels are:\n",
2316 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2320 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2321 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2329 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2330 int argc
, const char **argv
)
2333 const char *log_str
;
2340 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2341 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2346 log_str
= debug_level_to_string(loglevel
);
2347 printf("%s\n", log_str
);
2352 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2353 int argc
, const char **argv
)
2355 const char *db_name
;
2356 uint8_t db_flags
= 0;
2359 if (argc
< 1 || argc
> 2) {
2365 if (strcmp(argv
[1], "persistent") == 0) {
2366 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2367 } else if (strcmp(argv
[1], "readonly") == 0) {
2368 db_flags
= CTDB_DB_FLAGS_READONLY
;
2369 } else if (strcmp(argv
[1], "sticky") == 0) {
2370 db_flags
= CTDB_DB_FLAGS_STICKY
;
2371 } else if (strcmp(argv
[1], "replicated") == 0) {
2372 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2378 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2387 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2388 int argc
, const char **argv
)
2390 const char *db_name
;
2393 struct ctdb_node_map
*nodemap
;
2402 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2403 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2408 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2409 fprintf(stderr
, "Database cannot be detached"
2410 " when recovery is active\n");
2414 nodemap
= get_nodemap(ctdb
, false);
2415 if (nodemap
== NULL
) {
2419 for (j
=0; j
<nodemap
->num
; j
++) {
2422 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DISCONNECTED
) {
2425 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DELETED
) {
2428 if (nodemap
->node
[j
].flags
& NODE_FLAGS_INACTIVE
) {
2429 fprintf(stderr
, "Database cannot be detached on"
2430 " inactive (stopped or banned) node %u\n",
2431 nodemap
->node
[j
].pnn
);
2435 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2436 nodemap
->node
[j
].pnn
, TIMEOUT(),
2437 "AllowClientDBAttach", &value
);
2440 "Unable to get tunable AllowClientDBAttach"
2441 " from node %u\n", nodemap
->node
[j
].pnn
);
2447 "Database access is still active on node %u."
2448 " Set AllowclientDBAttach=0 on all nodes.\n",
2449 nodemap
->node
[j
].pnn
);
2455 for (i
=0; i
<argc
; i
++) {
2456 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2462 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2464 "Only volatile databases can be detached\n");
2468 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2470 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2478 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2479 int argc
, const char **argv
)
2481 const char *mem_str
;
2485 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2486 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2491 n
= write(1, mem_str
, strlen(mem_str
));
2492 if (n
< 0 || (size_t)n
!= strlen(mem_str
)) {
2493 fprintf(stderr
, "Failed to write talloc summary\n");
2500 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2502 bool *done
= (bool *)private_data
;
2506 len
= strnlen((const char *)data
.dptr
, data
.dsize
);
2507 n
= write(1, data
.dptr
, len
);
2508 if (n
< 0 || (size_t)n
!= len
) {
2509 fprintf(stderr
, "Failed to write talloc summary\n");
2515 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2516 int argc
, const char **argv
)
2518 struct ctdb_srvid_message msg
= { 0 };
2522 msg
.pnn
= ctdb
->pnn
;
2523 msg
.srvid
= next_srvid(ctdb
);
2525 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2526 msg
.srvid
, dump_memory
, &done
);
2531 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2532 ctdb
->cmd_pnn
, &msg
);
2537 ctdb_client_wait(ctdb
->ev
, &done
);
2541 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2542 int argc
, const char **argv
)
2547 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2548 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2553 printf("%u\n", pid
);
2557 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2558 const char *desc
, uint32_t flag
, bool set_flag
)
2560 struct ctdb_node_map
*nodemap
;
2563 nodemap
= get_nodemap(ctdb
, false);
2564 if (nodemap
== NULL
) {
2568 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2569 if (set_flag
== flag_is_set
) {
2571 fprintf(stderr
, "Node %u is already %s\n",
2572 ctdb
->cmd_pnn
, desc
);
2574 fprintf(stderr
, "Node %u is not %s\n",
2575 ctdb
->cmd_pnn
, desc
);
2583 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2584 uint32_t flag
, bool set_flag
)
2586 struct ctdb_node_map
*nodemap
;
2590 nodemap
= get_nodemap(ctdb
, true);
2591 if (nodemap
== NULL
) {
2593 "Failed to get nodemap, trying again\n");
2598 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2599 if (flag_is_set
== set_flag
) {
2607 struct ipreallocate_state
{
2612 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2615 struct ipreallocate_state
*state
=
2616 (struct ipreallocate_state
*)private_data
;
2618 if (data
.dsize
!= sizeof(int)) {
2623 state
->status
= *(int *)data
.dptr
;
2627 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2629 struct ctdb_srvid_message msg
= { 0 };
2630 struct ipreallocate_state state
;
2633 msg
.pnn
= ctdb
->pnn
;
2634 msg
.srvid
= next_srvid(ctdb
);
2637 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2639 ipreallocate_handler
, &state
);
2645 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2647 CTDB_BROADCAST_CONNECTED
,
2653 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2659 if (state
.status
>= 0) {
2668 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2673 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2674 int argc
, const char **argv
)
2682 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2683 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2688 ret
= ctdb_ctrl_disable_node(mem_ctx
,
2694 fprintf(stderr
, "Failed to disable node %u\n", ctdb
->cmd_pnn
);
2698 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2699 return ipreallocate(mem_ctx
, ctdb
);
2702 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2703 int argc
, const char **argv
)
2711 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2712 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2717 ret
= ctdb_ctrl_enable_node(mem_ctx
,
2723 fprintf(stderr
, "Failed to enable node %u\n", ctdb
->cmd_pnn
);
2727 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2728 return ipreallocate(mem_ctx
, ctdb
);
2731 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2732 int argc
, const char **argv
)
2740 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2741 NODE_FLAGS_STOPPED
, true);
2746 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2747 ctdb
->cmd_pnn
, TIMEOUT());
2749 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2753 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2754 return ipreallocate(mem_ctx
, ctdb
);
2757 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2758 int argc
, const char **argv
)
2766 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2767 NODE_FLAGS_STOPPED
, false);
2772 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2773 ctdb
->cmd_pnn
, TIMEOUT());
2775 fprintf(stderr
, "Failed to continue stopped node %u\n",
2780 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2781 return ipreallocate(mem_ctx
, ctdb
);
2784 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2785 int argc
, const char **argv
)
2787 struct ctdb_ban_state ban_state
;
2794 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2795 NODE_FLAGS_BANNED
, true);
2800 ban_state
.pnn
= ctdb
->cmd_pnn
;
2801 ban_state
.time
= smb_strtoul(argv
[0], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2806 if (ban_state
.time
== 0) {
2807 fprintf(stderr
, "Ban time cannot be zero\n");
2811 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2812 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2814 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2818 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2819 return ipreallocate(mem_ctx
, ctdb
);
2823 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2824 int argc
, const char **argv
)
2826 struct ctdb_ban_state ban_state
;
2833 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2834 NODE_FLAGS_BANNED
, false);
2839 ban_state
.pnn
= ctdb
->cmd_pnn
;
2842 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2843 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2845 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2849 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2850 return ipreallocate(mem_ctx
, ctdb
);
2854 static void wait_for_shutdown(void *private_data
)
2856 bool *done
= (bool *)private_data
;
2861 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2862 int argc
, const char **argv
)
2871 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2872 ctdb_client_set_disconnect_callback(ctdb
->client
,
2877 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2878 ctdb
->cmd_pnn
, TIMEOUT());
2880 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2884 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2885 ctdb_client_wait(ctdb
->ev
, &done
);
2891 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2892 uint32_t *generation
)
2896 struct ctdb_vnn_map
*vnnmap
;
2900 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2901 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2903 fprintf(stderr
, "Failed to find recovery master\n");
2907 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2908 recmaster
, TIMEOUT(), &recmode
);
2910 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2915 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2920 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2921 recmaster
, TIMEOUT(), &vnnmap
);
2923 fprintf(stderr
, "Failed to get generation from node %u\n",
2928 if (vnnmap
->generation
== INVALID_GENERATION
) {
2929 talloc_free(vnnmap
);
2934 *generation
= vnnmap
->generation
;
2935 talloc_free(vnnmap
);
2940 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2941 int argc
, const char **argv
)
2943 uint32_t generation
, next_generation
;
2950 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2955 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2956 ctdb
->cmd_pnn
, TIMEOUT(),
2957 CTDB_RECOVERY_ACTIVE
);
2959 fprintf(stderr
, "Failed to set recovery mode active\n");
2964 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2967 "Failed to confirm end of recovery\n");
2971 if (next_generation
!= generation
) {
2981 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2982 int argc
, const char **argv
)
2985 usage("ipreallocate");
2988 return ipreallocate(mem_ctx
, ctdb
);
2991 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2992 int argc
, const char **argv
)
2994 struct ctdb_addr_info addr_info
;
3001 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
3003 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3006 addr_info
.iface
= argv
[1];
3008 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3009 ctdb
->cmd_pnn
, TIMEOUT(),
3012 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3020 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3021 int argc
, const char **argv
)
3023 ctdb_sock_addr src
, dst
;
3026 if (argc
!= 0 && argc
!= 2) {
3031 struct ctdb_connection_list
*clist
;
3033 unsigned int num_failed
;
3035 /* Client first but the src/dst logic is confused */
3036 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3042 for (i
= 0; i
< clist
->num
; i
++) {
3043 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3044 &clist
->conn
[i
].dst
,
3053 if (num_failed
> 0) {
3054 fprintf(stderr
, "Failed to send %d tickles\n",
3063 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3065 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3069 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3071 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3075 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3077 fprintf(stderr
, "Failed to send tickle ack\n");
3084 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3085 int argc
, const char **argv
)
3087 ctdb_sock_addr addr
;
3088 struct ctdb_tickle_list
*tickles
;
3093 if (argc
< 1 || argc
> 2) {
3094 usage("gettickles");
3098 port
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3104 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3106 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3109 ctdb_sock_addr_set_port(&addr
, port
);
3111 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3112 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3115 fprintf(stderr
, "Failed to get list of connections\n");
3119 if (options
.machinereadable
) {
3120 printf("%s%s%s%s%s%s%s%s%s\n",
3122 "Source IP", options
.sep
,
3123 "Port", options
.sep
,
3124 "Destiation IP", options
.sep
,
3125 "Port", options
.sep
);
3126 for (i
=0; i
<tickles
->num
; i
++) {
3127 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3128 ctdb_sock_addr_to_string(
3129 mem_ctx
, &tickles
->conn
[i
].src
, false),
3131 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3133 ctdb_sock_addr_to_string(
3134 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3136 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3140 printf("Connections for IP: %s\n",
3141 ctdb_sock_addr_to_string(mem_ctx
,
3142 &tickles
->addr
, false));
3143 printf("Num connections: %u\n", tickles
->num
);
3144 for (i
=0; i
<tickles
->num
; i
++) {
3145 printf("SRC: %s DST: %s\n",
3146 ctdb_sock_addr_to_string(
3147 mem_ctx
, &tickles
->conn
[i
].src
, true),
3148 ctdb_sock_addr_to_string(
3149 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3153 talloc_free(tickles
);
3157 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3158 struct ctdb_connection
*conn
);
3160 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3162 struct process_clist_state
{
3163 struct ctdb_connection_list
*clist
;
3165 unsigned int num_failed
, num_total
;
3166 clist_reply_func reply_func
;
3169 static void process_clist_done(struct tevent_req
*subreq
);
3171 static struct tevent_req
*process_clist_send(
3172 TALLOC_CTX
*mem_ctx
,
3173 struct ctdb_context
*ctdb
,
3174 struct ctdb_connection_list
*clist
,
3175 clist_request_func request_func
,
3176 clist_reply_func reply_func
)
3178 struct tevent_req
*req
, *subreq
;
3179 struct process_clist_state
*state
;
3180 struct ctdb_req_control request
;
3183 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3188 state
->clist
= clist
;
3189 state
->reply_func
= reply_func
;
3191 for (i
= 0; i
< clist
->num
; i
++) {
3192 request_func(&request
, &clist
->conn
[i
]);
3193 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3194 ctdb
->client
, ctdb
->cmd_pnn
,
3195 TIMEOUT(), &request
);
3196 if (tevent_req_nomem(subreq
, req
)) {
3197 return tevent_req_post(req
, ctdb
->ev
);
3199 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3205 static void process_clist_done(struct tevent_req
*subreq
)
3207 struct tevent_req
*req
= tevent_req_callback_data(
3208 subreq
, struct tevent_req
);
3209 struct process_clist_state
*state
= tevent_req_data(
3210 req
, struct process_clist_state
);
3211 struct ctdb_reply_control
*reply
;
3215 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3216 TALLOC_FREE(subreq
);
3218 state
->num_failed
+= 1;
3222 ret
= state
->reply_func(reply
);
3224 state
->num_failed
+= 1;
3229 state
->num_total
+= 1;
3230 if (state
->num_total
== state
->clist
->num
) {
3231 tevent_req_done(req
);
3235 static int process_clist_recv(struct tevent_req
*req
)
3237 struct process_clist_state
*state
= tevent_req_data(
3238 req
, struct process_clist_state
);
3240 return state
->num_failed
;
3243 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3244 int argc
, const char **argv
)
3246 struct ctdb_connection conn
;
3249 if (argc
!= 0 && argc
!= 2) {
3254 struct ctdb_connection_list
*clist
;
3255 struct tevent_req
*req
;
3257 /* Client first but the src/dst logic is confused */
3258 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3262 if (clist
->num
== 0) {
3266 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3267 ctdb_req_control_tcp_add_delayed_update
,
3268 ctdb_reply_control_tcp_add_delayed_update
);
3274 tevent_req_poll(req
, ctdb
->ev
);
3277 ret
= process_clist_recv(req
);
3279 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3286 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3288 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3291 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3293 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3297 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3298 ctdb
->client
, ctdb
->cmd_pnn
,
3301 fprintf(stderr
, "Failed to register connection\n");
3308 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3309 int argc
, const char **argv
)
3311 struct ctdb_connection conn
;
3314 if (argc
!= 0 && argc
!= 2) {
3319 struct ctdb_connection_list
*clist
;
3320 struct tevent_req
*req
;
3322 /* Client first but the src/dst logic is confused */
3323 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3327 if (clist
->num
== 0) {
3331 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3332 ctdb_req_control_tcp_remove
,
3333 ctdb_reply_control_tcp_remove
);
3339 tevent_req_poll(req
, ctdb
->ev
);
3342 ret
= process_clist_recv(req
);
3344 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3351 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3353 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3356 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3358 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3362 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3363 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3365 fprintf(stderr
, "Failed to unregister connection\n");
3372 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3373 int argc
, const char **argv
)
3375 struct ctdb_node_map
*nodemap
;
3382 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3383 if (nodemap
== NULL
) {
3387 for (i
=0; i
<nodemap
->num
; i
++) {
3388 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3392 if (options
.machinereadable
) {
3393 printf("%s%u%s%s%s\n", options
.sep
,
3394 nodemap
->node
[i
].pnn
, options
.sep
,
3395 ctdb_sock_addr_to_string(
3396 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3400 ctdb_sock_addr_to_string(
3401 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3408 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3409 struct ctdb_node_map
*nodemap2
)
3413 if (nodemap1
->num
!= nodemap2
->num
) {
3417 for (i
=0; i
<nodemap1
->num
; i
++) {
3418 struct ctdb_node_and_flags
*n1
, *n2
;
3420 n1
= &nodemap1
->node
[i
];
3421 n2
= &nodemap2
->node
[i
];
3423 if ((n1
->pnn
!= n2
->pnn
) ||
3424 (n1
->flags
!= n2
->flags
) ||
3425 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3433 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3434 struct ctdb_node_map
*nm
,
3435 struct ctdb_node_map
*fnm
,
3439 bool check_failed
= false;
3443 for (i
=0; i
<nm
->num
; i
++) {
3444 if (i
>= fnm
->num
) {
3446 "Node %u (%s) missing from nodes file\n",
3448 ctdb_sock_addr_to_string(
3449 mem_ctx
, &nm
->node
[i
].addr
, false));
3450 check_failed
= true;
3453 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3454 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3455 /* Node remains deleted */
3459 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3460 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3461 /* Node not newly nor previously deleted */
3462 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3463 &fnm
->node
[i
].addr
)) {
3465 "Node %u has changed IP address"
3466 " (was %s, now %s)\n",
3468 ctdb_sock_addr_to_string(
3470 &nm
->node
[i
].addr
, false),
3471 ctdb_sock_addr_to_string(
3473 &fnm
->node
[i
].addr
, false));
3474 check_failed
= true;
3476 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3478 "WARNING: Node %u is disconnected."
3479 " You MUST fix this node manually!\n",
3486 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3487 /* Node is being deleted */
3488 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3490 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3492 "ERROR: Node %u is still connected\n",
3494 check_failed
= true;
3499 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3500 /* Node was previously deleted */
3501 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3508 "ERROR: Nodes will not be reloaded due to previous error\n");
3512 /* Leftover nodes in file are NEW */
3513 for (; i
< fnm
->num
; i
++) {
3514 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3521 struct disable_recoveries_state
{
3523 unsigned int node_count
;
3529 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3532 struct disable_recoveries_state
*state
=
3533 (struct disable_recoveries_state
*)private_data
;
3537 if (data
.dsize
!= sizeof(int)) {
3542 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3543 ret
= *(int *)data
.dptr
;
3545 state
->status
= ret
;
3549 for (i
=0; i
<state
->node_count
; i
++) {
3550 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
3551 state
->reply
[i
] = true;
3557 for (i
=0; i
<state
->node_count
; i
++) {
3558 if (! state
->reply
[i
]) {
3559 state
->done
= false;
3565 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3566 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3568 struct ctdb_disable_message disable
= { 0 };
3569 struct disable_recoveries_state state
;
3572 disable
.pnn
= ctdb
->pnn
;
3573 disable
.srvid
= next_srvid(ctdb
);
3574 disable
.timeout
= timeout
;
3576 state
.pnn_list
= pnn_list
;
3577 state
.node_count
= count
;
3580 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3581 if (state
.reply
== NULL
) {
3585 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3587 disable_recoveries_handler
,
3593 for (i
=0; i
<count
; i
++) {
3594 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3603 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3605 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3607 ret
= (state
.status
>= 0 ? 0 : 1);
3611 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3612 disable
.srvid
, &state
);
3616 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3617 int argc
, const char **argv
)
3619 struct ctdb_node_map
*nodemap
= NULL
;
3620 struct ctdb_node_map
*file_nodemap
;
3621 struct ctdb_node_map
*remote_nodemap
;
3622 struct ctdb_req_control request
;
3623 struct ctdb_reply_control
**reply
;
3630 nodemap
= get_nodemap(ctdb
, false);
3631 if (nodemap
== NULL
) {
3635 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3636 if (file_nodemap
== NULL
) {
3640 for (i
=0; i
<nodemap
->num
; i
++) {
3641 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3645 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3646 nodemap
->node
[i
].pnn
, TIMEOUT(),
3650 "ERROR: Failed to get nodes file from node %u\n",
3651 nodemap
->node
[i
].pnn
);
3655 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3657 "ERROR: Nodes file on node %u differs"
3658 " from current node (%u)\n",
3659 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3664 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3670 fprintf(stderr
, "No change in nodes file,"
3671 " skipping unnecessary reload\n");
3675 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3676 mem_ctx
, &pnn_list
);
3678 fprintf(stderr
, "Memory allocation error\n");
3682 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3685 fprintf(stderr
, "Failed to disable recoveries\n");
3689 ctdb_req_control_reload_nodes_file(&request
);
3690 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3691 pnn_list
, count
, TIMEOUT(),
3692 &request
, NULL
, &reply
);
3694 bool failed
= false;
3697 for (j
=0; j
<count
; j
++) {
3698 ret
= ctdb_reply_control_reload_nodes_file(reply
[j
]);
3701 "Node %u failed to reload nodes\n",
3708 "You MUST fix failed nodes manually!\n");
3712 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3714 fprintf(stderr
, "Failed to enable recoveries\n");
3721 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3722 ctdb_sock_addr
*addr
, uint32_t pnn
)
3724 struct ctdb_public_ip_list
*pubip_list
;
3725 struct ctdb_public_ip pubip
;
3726 struct ctdb_node_map
*nodemap
;
3727 struct ctdb_req_control request
;
3732 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3733 CTDB_BROADCAST_CONNECTED
,
3734 2*options
.timelimit
);
3736 fprintf(stderr
, "Failed to disable IP check\n");
3740 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3741 pnn
, TIMEOUT(), false, &pubip_list
);
3743 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3748 for (i
=0; i
<pubip_list
->num
; i
++) {
3749 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3754 if (i
== pubip_list
->num
) {
3755 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3756 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3760 nodemap
= get_nodemap(ctdb
, false);
3761 if (nodemap
== NULL
) {
3765 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3767 fprintf(stderr
, "Memory allocation error\n");
3773 ctdb_req_control_release_ip(&request
, &pubip
);
3775 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3776 pnn_list
, count
, TIMEOUT(),
3777 &request
, NULL
, NULL
);
3779 fprintf(stderr
, "Failed to release IP on nodes\n");
3783 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3784 pnn
, TIMEOUT(), &pubip
);
3786 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3793 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3794 int argc
, const char **argv
)
3796 ctdb_sock_addr addr
;
3805 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3807 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3811 pnn
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3812 if (pnn
== CTDB_UNKNOWN_PNN
|| ret
!= 0) {
3813 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3817 while (retries
< 5) {
3818 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3828 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3836 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3841 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3842 CTDB_BROADCAST_CONNECTED
, pnn
);
3845 "Failed to ask recovery master to distribute IPs\n");
3852 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3853 int argc
, const char **argv
)
3855 ctdb_sock_addr addr
;
3856 struct ctdb_public_ip_list
*pubip_list
;
3857 struct ctdb_addr_info addr_info
;
3858 unsigned int mask
, i
;
3859 int ret
, retries
= 0;
3865 ret
= ctdb_sock_addr_mask_from_string(argv
[0], &addr
, &mask
);
3867 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3871 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3872 ctdb
->cmd_pnn
, TIMEOUT(),
3873 false, &pubip_list
);
3875 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3880 for (i
=0; i
<pubip_list
->num
; i
++) {
3881 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3882 fprintf(stderr
, "Node already knows about IP %s\n",
3883 ctdb_sock_addr_to_string(mem_ctx
,
3889 addr_info
.addr
= addr
;
3890 addr_info
.mask
= mask
;
3891 addr_info
.iface
= argv
[1];
3893 while (retries
< 5) {
3894 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3895 ctdb
->cmd_pnn
, TIMEOUT(),
3906 fprintf(stderr
, "Failed to add public IP to node %u."
3907 " Giving up\n", ctdb
->cmd_pnn
);
3911 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3919 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3920 int argc
, const char **argv
)
3922 ctdb_sock_addr addr
;
3923 struct ctdb_public_ip_list
*pubip_list
;
3924 struct ctdb_addr_info addr_info
;
3932 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3934 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3938 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3939 ctdb
->cmd_pnn
, TIMEOUT(),
3940 false, &pubip_list
);
3942 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3947 for (i
=0; i
<pubip_list
->num
; i
++) {
3948 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3953 if (i
== pubip_list
->num
) {
3954 fprintf(stderr
, "Node does not know about IP address %s\n",
3955 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
3959 addr_info
.addr
= addr
;
3961 addr_info
.iface
= NULL
;
3963 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3964 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
3966 fprintf(stderr
, "Failed to delete public IP from node %u\n",
3974 #define DB_VERSION 3
3975 #define MAX_DB_NAME 64
3976 #define MAX_REC_BUFFER_SIZE (100*1000)
3979 unsigned long version
;
3981 unsigned long flags
;
3984 char name
[MAX_DB_NAME
];
3987 struct backup_state
{
3988 TALLOC_CTX
*mem_ctx
;
3989 struct ctdb_rec_buffer
*recbuf
;
3992 unsigned int nbuf
, nrec
;
3995 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
3996 TDB_DATA key
, TDB_DATA data
, void *private_data
)
3998 struct backup_state
*state
= (struct backup_state
*)private_data
;
4002 if (state
->recbuf
== NULL
) {
4003 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4005 if (state
->recbuf
== NULL
) {
4010 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4016 len
= ctdb_rec_buffer_len(state
->recbuf
);
4017 if (len
< MAX_REC_BUFFER_SIZE
) {
4021 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4023 fprintf(stderr
, "Failed to write records to backup file\n");
4028 state
->nrec
+= state
->recbuf
->count
;
4029 TALLOC_FREE(state
->recbuf
);
4034 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4035 int argc
, const char **argv
)
4037 const char *db_name
;
4038 struct ctdb_db_context
*db
;
4041 struct backup_state state
;
4042 struct db_header db_hdr
;
4049 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4053 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4056 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4060 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4063 fprintf(stderr
, "Failed to open file %s for writing\n",
4068 /* Write empty header first */
4069 ZERO_STRUCT(db_hdr
);
4070 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4074 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4078 state
.mem_ctx
= mem_ctx
;
4079 state
.recbuf
= NULL
;
4084 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4086 fprintf(stderr
, "Failed to collect records from DB %s\n",
4092 if (state
.recbuf
!= NULL
) {
4093 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4096 "Failed to write records to backup file\n");
4102 state
.nrec
+= state
.recbuf
->count
;
4103 TALLOC_FREE(state
.recbuf
);
4106 db_hdr
.version
= DB_VERSION
;
4107 db_hdr
.timestamp
= time(NULL
);
4108 db_hdr
.flags
= db_flags
;
4109 db_hdr
.nbuf
= state
.nbuf
;
4110 db_hdr
.nrec
= state
.nrec
;
4111 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4113 lseek(fd
, 0, SEEK_SET
);
4114 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4118 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4123 printf("Database backed up to %s\n", argv
[1]);
4127 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4128 int argc
, const char **argv
)
4130 const char *db_name
= NULL
;
4131 struct ctdb_db_context
*db
;
4132 struct db_header db_hdr
;
4133 struct ctdb_node_map
*nodemap
;
4134 struct ctdb_req_control request
;
4135 struct ctdb_reply_control
**reply
;
4136 struct ctdb_transdb wipedb
;
4137 struct ctdb_pulldb_ext pulldb
;
4138 struct ctdb_rec_buffer
*recbuf
;
4139 uint32_t generation
;
4144 unsigned long i
, count
;
4148 if (argc
< 1 || argc
> 2) {
4152 fd
= open(argv
[0], O_RDONLY
, 0600);
4155 fprintf(stderr
, "Failed to open file %s for reading\n",
4164 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4168 fprintf(stderr
, "Failed to read db header from file %s\n",
4172 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4174 if (db_hdr
.version
!= DB_VERSION
) {
4176 "Wrong version of backup file, expected %u, got %lu\n",
4177 DB_VERSION
, db_hdr
.version
);
4182 if (db_name
== NULL
) {
4183 db_name
= db_hdr
.name
;
4186 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4187 localtime(&db_hdr
.timestamp
));
4188 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4190 db_flags
= db_hdr
.flags
& 0xff;
4191 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4194 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4199 nodemap
= get_nodemap(ctdb
, false);
4200 if (nodemap
== NULL
) {
4201 fprintf(stderr
, "Failed to get nodemap\n");
4206 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4208 fprintf(stderr
, "Failed to get current generation\n");
4213 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4220 wipedb
.db_id
= ctdb_db_id(db
);
4221 wipedb
.tid
= generation
;
4223 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4224 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4225 ctdb
->client
, pnn_list
, count
,
4226 TIMEOUT(), &request
, NULL
, NULL
);
4232 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4233 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4234 pnn_list
, count
, TIMEOUT(),
4235 &request
, NULL
, NULL
);
4240 ctdb_req_control_wipe_database(&request
, &wipedb
);
4241 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4242 pnn_list
, count
, TIMEOUT(),
4243 &request
, NULL
, NULL
);
4248 pulldb
.db_id
= ctdb_db_id(db
);
4250 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4252 ctdb_req_control_db_push_start(&request
, &pulldb
);
4253 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4254 pnn_list
, count
, TIMEOUT(),
4255 &request
, NULL
, NULL
);
4260 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4261 struct ctdb_req_message message
;
4265 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4270 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4271 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4272 if (data
.dptr
== NULL
) {
4276 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4278 message
.srvid
= pulldb
.srvid
;
4279 message
.data
.data
= data
;
4281 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4289 talloc_free(recbuf
);
4290 talloc_free(data
.dptr
);
4293 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4294 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4295 pnn_list
, count
, TIMEOUT(),
4296 &request
, NULL
, &reply
);
4301 for (i
=0; i
<count
; i
++) {
4302 uint32_t num_records
;
4304 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4307 fprintf(stderr
, "Invalid response from node %u\n",
4312 if (num_records
!= db_hdr
.nrec
) {
4313 fprintf(stderr
, "Node %u received %u of %lu records\n",
4314 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4319 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4320 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4321 pnn_list
, count
, TIMEOUT(),
4322 &request
, NULL
, NULL
);
4327 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4328 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4329 pnn_list
, count
, TIMEOUT(),
4330 &request
, NULL
, NULL
);
4335 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4336 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4337 ctdb
->client
, pnn_list
, count
,
4338 TIMEOUT(), &request
, NULL
, NULL
);
4343 printf("Database %s restored\n", db_name
);
4350 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4351 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4355 struct dumpdbbackup_state
{
4356 ctdb_rec_parser_func_t parser
;
4357 struct dump_record_state sub_state
;
4360 static int dumpdbbackup_handler(uint32_t reqid
,
4361 struct ctdb_ltdb_header
*header
,
4362 TDB_DATA key
, TDB_DATA data
,
4365 struct dumpdbbackup_state
*state
=
4366 (struct dumpdbbackup_state
*)private_data
;
4367 struct ctdb_ltdb_header hdr
;
4370 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4375 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4378 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4379 int argc
, const char **argv
)
4381 struct db_header db_hdr
;
4383 struct dumpdbbackup_state state
;
4389 usage("dumpbackup");
4392 fd
= open(argv
[0], O_RDONLY
, 0600);
4395 fprintf(stderr
, "Failed to open file %s for reading\n",
4400 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4404 fprintf(stderr
, "Failed to read db header from file %s\n",
4408 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4410 if (db_hdr
.version
!= DB_VERSION
) {
4412 "Wrong version of backup file, expected %u, got %lu\n",
4413 DB_VERSION
, db_hdr
.version
);
4418 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4419 localtime(&db_hdr
.timestamp
));
4420 printf("Dumping database %s from backup @ %s\n",
4421 db_hdr
.name
, timebuf
);
4423 state
.parser
= dump_record
;
4424 state
.sub_state
.count
= 0;
4426 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4427 struct ctdb_rec_buffer
*recbuf
;
4429 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4431 fprintf(stderr
, "Failed to read records\n");
4436 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4439 fprintf(stderr
, "Failed to dump records\n");
4446 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4450 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4451 int argc
, const char **argv
)
4453 const char *db_name
;
4454 struct ctdb_db_context
*db
;
4457 struct ctdb_node_map
*nodemap
;
4458 struct ctdb_req_control request
;
4459 struct ctdb_transdb wipedb
;
4460 uint32_t generation
;
4468 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4472 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4475 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4479 nodemap
= get_nodemap(ctdb
, false);
4480 if (nodemap
== NULL
) {
4481 fprintf(stderr
, "Failed to get nodemap\n");
4485 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4487 fprintf(stderr
, "Failed to get current generation\n");
4491 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4497 ctdb_req_control_db_freeze(&request
, db_id
);
4498 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4499 ctdb
->client
, pnn_list
, count
,
4500 TIMEOUT(), &request
, NULL
, NULL
);
4505 wipedb
.db_id
= db_id
;
4506 wipedb
.tid
= generation
;
4508 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4509 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4510 pnn_list
, count
, TIMEOUT(),
4511 &request
, NULL
, NULL
);
4516 ctdb_req_control_wipe_database(&request
, &wipedb
);
4517 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4518 pnn_list
, count
, TIMEOUT(),
4519 &request
, NULL
, NULL
);
4524 ctdb_req_control_db_set_healthy(&request
, db_id
);
4525 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4526 pnn_list
, count
, TIMEOUT(),
4527 &request
, NULL
, NULL
);
4532 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4533 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4534 pnn_list
, count
, TIMEOUT(),
4535 &request
, NULL
, NULL
);
4540 ctdb_req_control_db_thaw(&request
, db_id
);
4541 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4542 ctdb
->client
, pnn_list
, count
,
4543 TIMEOUT(), &request
, NULL
, NULL
);
4548 printf("Database %s wiped\n", db_name
);
4553 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4554 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4558 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4559 int argc
, const char **argv
)
4564 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4565 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4570 print_pnn(recmaster
);
4575 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4576 int argc
, const char **argv
)
4578 char *t
, *event_helper
= NULL
;
4580 t
= getenv("CTDB_EVENT_HELPER");
4582 event_helper
= talloc_strdup(mem_ctx
, t
);
4584 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb-event",
4585 CTDB_HELPER_BINDIR
);
4588 if (event_helper
== NULL
) {
4589 fprintf(stderr
, "Unable to set event daemon helper\n");
4593 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4597 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4598 int argc
, const char **argv
)
4600 const char *new_argv
[4];
4603 usage("scriptstatus");
4606 new_argv
[0] = "status";
4607 new_argv
[1] = "legacy";
4608 new_argv
[2] = (argc
== 0) ? "monitor" : argv
[0];
4611 (void) control_event(mem_ctx
, ctdb
, 3, new_argv
);
4615 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4616 int argc
, const char **argv
)
4618 char *t
, *natgw_helper
= NULL
;
4624 t
= getenv("CTDB_NATGW_HELPER");
4626 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4628 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4629 CTDB_HELPER_BINDIR
);
4632 if (natgw_helper
== NULL
) {
4633 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4637 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4642 * Find the PNN of the current node
4643 * discover the pnn by loading the nodes file and try to bind
4644 * to all addresses one at a time until the ip address is found.
4646 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4648 struct ctdb_node_map
*nodemap
;
4651 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4652 if (nodemap
== NULL
) {
4656 for (i
=0; i
<nodemap
->num
; i
++) {
4657 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4660 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4662 *pnn
= nodemap
->node
[i
].pnn
;
4664 talloc_free(nodemap
);
4669 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4670 talloc_free(nodemap
);
4674 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4675 int argc
, const char **argv
)
4677 const char *reclock
;
4681 usage("getreclock");
4684 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4685 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4690 if (reclock
!= NULL
) {
4691 printf("%s\n", reclock
);
4697 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4698 struct ctdb_context
*ctdb
,
4699 int argc
, const char **argv
)
4701 uint32_t lmasterrole
= 0;
4705 usage("setlmasterrole");
4708 if (strcmp(argv
[0], "on") == 0) {
4710 } else if (strcmp(argv
[0], "off") == 0) {
4713 usage("setlmasterrole");
4716 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4717 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4725 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4726 struct ctdb_context
*ctdb
,
4727 int argc
, const char **argv
)
4729 uint32_t recmasterrole
= 0;
4733 usage("setrecmasterrole");
4736 if (strcmp(argv
[0], "on") == 0) {
4738 } else if (strcmp(argv
[0], "off") == 0) {
4741 usage("setrecmasterrole");
4744 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4745 ctdb
->cmd_pnn
, TIMEOUT(),
4754 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4755 struct ctdb_context
*ctdb
,
4756 int argc
, const char **argv
)
4763 usage("setdbreadonly");
4766 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4770 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4771 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4775 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4776 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4784 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4785 int argc
, const char **argv
)
4792 usage("setdbsticky");
4795 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4799 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4800 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4804 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4805 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4813 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4814 int argc
, const char **argv
)
4816 const char *db_name
;
4817 struct ctdb_db_context
*db
;
4818 struct ctdb_transaction_handle
*h
;
4827 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4832 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4833 fprintf(stderr
, "Transactions not supported on DB %s\n",
4838 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4841 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4845 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4847 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4851 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4852 TIMEOUT(), db
, true, &h
);
4854 fprintf(stderr
, "Failed to start transaction on db %s\n",
4859 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4861 fprintf(stderr
, "Failed to read record for key %s\n",
4863 ctdb_transaction_cancel(h
);
4867 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4869 ctdb_transaction_cancel(h
);
4873 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4874 int argc
, const char **argv
)
4876 const char *db_name
;
4877 struct ctdb_db_context
*db
;
4878 struct ctdb_transaction_handle
*h
;
4887 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4892 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4893 fprintf(stderr
, "Transactions not supported on DB %s\n",
4898 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4901 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4905 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4907 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4911 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4913 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
4917 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4918 TIMEOUT(), db
, false, &h
);
4920 fprintf(stderr
, "Failed to start transaction on db %s\n",
4925 ret
= ctdb_transaction_store_record(h
, key
, data
);
4927 fprintf(stderr
, "Failed to store record for key %s\n",
4929 ctdb_transaction_cancel(h
);
4933 ret
= ctdb_transaction_commit(h
);
4935 fprintf(stderr
, "Failed to commit transaction on db %s\n",
4937 ctdb_transaction_cancel(h
);
4944 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4945 int argc
, const char **argv
)
4947 const char *db_name
;
4948 struct ctdb_db_context
*db
;
4949 struct ctdb_transaction_handle
*h
;
4958 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4963 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4964 fprintf(stderr
, "Transactions not supported on DB %s\n",
4969 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4972 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4976 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4978 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4982 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4983 TIMEOUT(), db
, false, &h
);
4985 fprintf(stderr
, "Failed to start transaction on db %s\n",
4990 ret
= ctdb_transaction_delete_record(h
, key
);
4992 fprintf(stderr
, "Failed to delete record for key %s\n",
4994 ctdb_transaction_cancel(h
);
4998 ret
= ctdb_transaction_commit(h
);
5000 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5002 ctdb_transaction_cancel(h
);
5009 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5017 /* Skip whitespace */
5018 n
= strspn(*ptr
, " \t");
5022 /* Quoted ASCII string - no wide characters! */
5024 n
= strcspn(t
, "\"");
5027 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5034 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5038 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5045 #define MAX_LINE_SIZE 1024
5047 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5048 TDB_DATA
*key
, TDB_DATA
*value
)
5050 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5054 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5060 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5061 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5062 /* Line Ignored but not EOF */
5068 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5070 /* Line Ignored but not EOF */
5071 talloc_free(key
->dptr
);
5079 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5080 int argc
, const char **argv
)
5082 const char *db_name
;
5083 struct ctdb_db_context
*db
;
5084 struct ctdb_transaction_handle
*h
;
5087 TDB_DATA key
= tdb_null
, value
= tdb_null
;
5090 if (argc
< 1 || argc
> 2) {
5094 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5099 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5100 fprintf(stderr
, "Transactions not supported on DB %s\n",
5106 file
= fopen(argv
[1], "r");
5108 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5115 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5118 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5122 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5123 TIMEOUT(), db
, false, &h
);
5125 fprintf(stderr
, "Failed to start transaction on db %s\n",
5130 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5131 if (key
.dsize
!= 0) {
5132 ret
= ctdb_transaction_store_record(h
, key
, value
);
5134 fprintf(stderr
, "Failed to store record\n");
5135 ctdb_transaction_cancel(h
);
5138 talloc_free(key
.dptr
);
5139 talloc_free(value
.dptr
);
5143 ret
= ctdb_transaction_commit(h
);
5145 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5147 ctdb_transaction_cancel(h
);
5151 if (file
!= stdin
) {
5157 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5158 int argc
, const char **argv
)
5160 struct tdb_context
*tdb
;
5162 struct ctdb_ltdb_header header
;
5165 if (argc
< 2 || argc
> 3) {
5169 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5171 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5175 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5177 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5182 data
= tdb_fetch(tdb
, key
);
5183 if (data
.dptr
== NULL
) {
5184 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5189 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5190 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5201 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5203 fprintf(stderr
, "Failed to open output file %s\n",
5208 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5209 if (nwritten
== -1 ||
5210 (size_t)nwritten
!= data
.dsize
) {
5211 fprintf(stderr
, "Failed to write record to file\n");
5220 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5222 fprintf(stderr
, "Failed to parse header from data\n");
5226 dump_ltdb_header(&header
);
5227 dump_tdb_data("data", data
);
5232 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5233 int argc
, const char **argv
)
5235 struct tdb_context
*tdb
;
5236 TDB_DATA key
, data
[2], value
;
5237 struct ctdb_ltdb_header header
;
5238 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5242 if (argc
< 3 || argc
> 5) {
5246 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5248 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5252 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5254 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5259 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5261 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5266 ZERO_STRUCT(header
);
5269 header
.rsn
= (uint64_t)smb_strtoull(argv
[3],
5279 header
.dmaster
= (uint32_t)atol(argv
[4]);
5282 header
.flags
= (uint32_t)atol(argv
[5]);
5285 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5288 data
[0].dptr
= header_buf
;
5290 data
[1].dsize
= value
.dsize
;
5291 data
[1].dptr
= value
.dptr
;
5293 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5295 fprintf(stderr
, "Failed to write record %s to file %s\n",
5304 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5305 int argc
, const char **argv
)
5307 const char *db_name
;
5308 struct ctdb_db_context
*db
;
5309 struct ctdb_record_handle
*h
;
5312 bool readonly
= false;
5315 if (argc
< 2 || argc
> 3) {
5320 if (strcmp(argv
[2], "readonly") == 0) {
5327 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5331 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5332 fprintf(stderr
, "DB %s is not a volatile database\n",
5337 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5340 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5344 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5346 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5350 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5351 db
, key
, readonly
, &h
, NULL
, &data
);
5353 fprintf(stderr
, "Failed to read record for key %s\n",
5356 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5357 (int)data
.dsize
, data
.dptr
);
5364 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5365 int argc
, const char **argv
)
5367 const char *db_name
;
5368 struct ctdb_db_context
*db
;
5369 struct ctdb_record_handle
*h
;
5378 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5382 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5383 fprintf(stderr
, "DB %s is not a volatile database\n",
5388 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5391 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5395 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5397 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5401 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5403 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5407 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5408 db
, key
, false, &h
, NULL
, NULL
);
5410 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5414 ret
= ctdb_store_record(h
, data
);
5416 fprintf(stderr
, "Failed to store record for key %s\n",
5424 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5425 int argc
, const char **argv
)
5427 const char *db_name
;
5428 struct ctdb_db_context
*db
;
5429 struct ctdb_record_handle
*h
;
5438 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5442 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5443 fprintf(stderr
, "DB %s is not a volatile database\n",
5448 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5451 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5455 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5457 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5461 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5462 db
, key
, false, &h
, NULL
, &data
);
5464 fprintf(stderr
, "Failed to fetch record for key %s\n",
5469 ret
= ctdb_delete_record(h
);
5471 fprintf(stderr
, "Failed to delete record for key %s\n",
5479 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5480 int argc
, const char **argv
)
5482 struct sockaddr_in sin
;
5488 usage("chktcpport");
5491 port
= atoi(argv
[0]);
5493 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5495 fprintf(stderr
, "Failed to open local socket\n");
5499 v
= fcntl(s
, F_GETFL
, 0);
5500 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5501 fprintf(stderr
, "Unable to set socket non-blocking\n");
5506 bzero(&sin
, sizeof(sin
));
5507 sin
.sin_family
= AF_INET
;
5508 sin
.sin_port
= htons(port
);
5509 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5512 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5519 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5520 int argc
, const char **argv
)
5523 const char *db_name
;
5528 usage("getdbseqnum");
5531 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5535 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5536 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5539 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5544 printf("0x%"PRIx64
"\n", seqnum
);
5548 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5549 int argc
, const char **argv
)
5551 const char *nodestring
= NULL
;
5552 struct ctdb_node_map
*nodemap
;
5555 bool print_hdr
= false;
5558 usage("nodestatus");
5562 nodestring
= argv
[0];
5563 if (strcmp(nodestring
, "all") == 0) {
5568 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5572 if (options
.machinereadable
) {
5573 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5575 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5579 for (i
=0; i
<nodemap
->num
; i
++) {
5580 uint32_t flags
= nodemap
->node
[i
].flags
;
5582 if ((flags
& NODE_FLAGS_DELETED
) != 0) {
5595 } db_stats_fields
[] = {
5596 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5597 DBSTATISTICS_FIELD(db_ro_delegations
),
5598 DBSTATISTICS_FIELD(db_ro_revokes
),
5599 DBSTATISTICS_FIELD(locks
.num_calls
),
5600 DBSTATISTICS_FIELD(locks
.num_current
),
5601 DBSTATISTICS_FIELD(locks
.num_pending
),
5602 DBSTATISTICS_FIELD(locks
.num_failed
),
5605 static void print_dbstatistics(const char *db_name
,
5606 struct ctdb_db_statistics
*s
)
5609 const char *prefix
= NULL
;
5612 printf("DB Statistics %s\n", db_name
);
5614 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5615 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5616 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5618 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5619 prefix
= db_stats_fields
[i
].name
;
5620 printf(" %*.*s\n", preflen
-1, preflen
-1,
5621 db_stats_fields
[i
].name
);
5626 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5627 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5628 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5631 printf(" hop_count_buckets:");
5632 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5633 printf(" %d", s
->hop_count_bucket
[i
]);
5637 printf(" lock_buckets:");
5638 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5639 printf(" %d", s
->locks
.buckets
[i
]);
5643 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5644 "locks_latency MIN/AVG/MAX",
5645 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5646 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5648 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5649 "vacuum_latency MIN/AVG/MAX",
5650 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5651 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5653 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5654 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5656 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5657 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5658 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5664 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5665 int argc
, const char **argv
)
5668 const char *db_name
;
5669 struct ctdb_db_statistics
*dbstats
;
5673 usage("dbstatistics");
5676 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5680 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5681 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5684 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5689 print_dbstatistics(db_name
, dbstats
);
5693 struct disable_takeover_runs_state
{
5695 unsigned int node_count
;
5701 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5704 struct disable_takeover_runs_state
*state
=
5705 (struct disable_takeover_runs_state
*)private_data
;
5709 if (data
.dsize
!= sizeof(int)) {
5714 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5715 ret
= *(int *)data
.dptr
;
5717 state
->status
= ret
;
5721 for (i
=0; i
<state
->node_count
; i
++) {
5722 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
5723 state
->reply
[i
] = true;
5729 for (i
=0; i
<state
->node_count
; i
++) {
5730 if (! state
->reply
[i
]) {
5731 state
->done
= false;
5737 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5738 struct ctdb_context
*ctdb
, uint32_t timeout
,
5739 uint32_t *pnn_list
, int count
)
5741 struct ctdb_disable_message disable
= { 0 };
5742 struct disable_takeover_runs_state state
;
5745 disable
.pnn
= ctdb
->pnn
;
5746 disable
.srvid
= next_srvid(ctdb
);
5747 disable
.timeout
= timeout
;
5749 state
.pnn_list
= pnn_list
;
5750 state
.node_count
= count
;
5753 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5754 if (state
.reply
== NULL
) {
5758 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5760 disable_takeover_run_handler
,
5766 for (i
=0; i
<count
; i
++) {
5767 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5776 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5778 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5780 ret
= (state
.status
>= 0 ? 0 : 1);
5784 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5785 disable
.srvid
, &state
);
5789 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5790 int argc
, const char **argv
)
5792 const char *nodestring
= NULL
;
5793 struct ctdb_node_map
*nodemap
, *nodemap2
;
5794 struct ctdb_req_control request
;
5795 uint32_t *pnn_list
, *pnn_list2
;
5796 int ret
, count
, count2
;
5803 nodestring
= argv
[0];
5806 nodemap
= get_nodemap(ctdb
, false);
5807 if (nodemap
== NULL
) {
5811 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5815 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5816 mem_ctx
, &pnn_list
);
5818 fprintf(stderr
, "Memory allocation error\n");
5822 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5823 mem_ctx
, &pnn_list2
);
5825 fprintf(stderr
, "Memory allocation error\n");
5829 /* Disable takeover runs on all connected nodes. A reply
5830 * indicating success is needed from each node so all nodes
5831 * will need to be active.
5833 * A check could be added to not allow reloading of IPs when
5834 * there are disconnected nodes. However, this should
5835 * probably be left up to the administrator.
5837 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5840 fprintf(stderr
, "Failed to disable takeover runs\n");
5844 /* Now tell all the desired nodes to reload their public IPs.
5845 * Keep trying this until it succeeds. This assumes all
5846 * failures are transient, which might not be true...
5848 ctdb_req_control_reload_public_ips(&request
);
5849 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5850 pnn_list2
, count2
, TIMEOUT(),
5851 &request
, NULL
, NULL
);
5853 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5856 /* It isn't strictly necessary to wait until takeover runs are
5857 * re-enabled but doing so can't hurt.
5859 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5861 fprintf(stderr
, "Failed to enable takeover runs\n");
5865 return ipreallocate(mem_ctx
, ctdb
);
5869 static const struct ctdb_cmd
{
5871 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5872 bool without_daemon
; /* can be run without daemon running ? */
5873 bool remote
; /* can be run on remote nodes */
5876 } ctdb_commands
[] = {
5877 { "version", control_version
, true, false,
5878 "show version of ctdb", NULL
},
5879 { "status", control_status
, false, true,
5880 "show node status", NULL
},
5881 { "uptime", control_uptime
, false, true,
5882 "show node uptime", NULL
},
5883 { "ping", control_ping
, false, true,
5884 "ping a node", NULL
},
5885 { "runstate", control_runstate
, false, true,
5886 "get/check runstate of a node",
5887 "[setup|first_recovery|startup|running]" },
5888 { "getvar", control_getvar
, false, true,
5889 "get a tunable variable", "<name>" },
5890 { "setvar", control_setvar
, false, true,
5891 "set a tunable variable", "<name> <value>" },
5892 { "listvars", control_listvars
, false, true,
5893 "list tunable variables", NULL
},
5894 { "statistics", control_statistics
, false, true,
5895 "show ctdb statistics", NULL
},
5896 { "statisticsreset", control_statistics_reset
, false, true,
5897 "reset ctdb statistics", NULL
},
5898 { "stats", control_stats
, false, true,
5899 "show rolling statistics", "[count]" },
5900 { "ip", control_ip
, false, true,
5901 "show public ips", "[all]" },
5902 { "ipinfo", control_ipinfo
, false, true,
5903 "show public ip details", "<ip>" },
5904 { "ifaces", control_ifaces
, false, true,
5905 "show interfaces", NULL
},
5906 { "setifacelink", control_setifacelink
, false, true,
5907 "set interface link status", "<iface> up|down" },
5908 { "process-exists", control_process_exists
, false, true,
5909 "check if a process exists on a node", "<pid> [<srvid>]" },
5910 { "getdbmap", control_getdbmap
, false, true,
5911 "show attached databases", NULL
},
5912 { "getdbstatus", control_getdbstatus
, false, true,
5913 "show database status", "<dbname|dbid>" },
5914 { "catdb", control_catdb
, false, false,
5915 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5916 { "cattdb", control_cattdb
, false, false,
5917 "dump local ctdb database", "<dbname|dbid>" },
5918 { "getcapabilities", control_getcapabilities
, false, true,
5919 "show node capabilities", NULL
},
5920 { "pnn", control_pnn
, false, false,
5921 "show the pnn of the currnet node", NULL
},
5922 { "lvs", control_lvs
, false, false,
5923 "show lvs configuration", "leader|list|status" },
5924 { "setdebug", control_setdebug
, false, true,
5925 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5926 { "getdebug", control_getdebug
, false, true,
5927 "get debug level", NULL
},
5928 { "attach", control_attach
, false, false,
5929 "attach a database", "<dbname> [persistent|replicated]" },
5930 { "detach", control_detach
, false, false,
5931 "detach database(s)", "<dbname|dbid> ..." },
5932 { "dumpmemory", control_dumpmemory
, false, true,
5933 "dump ctdbd memory map", NULL
},
5934 { "rddumpmemory", control_rddumpmemory
, false, true,
5935 "dump recoverd memory map", NULL
},
5936 { "getpid", control_getpid
, false, true,
5937 "get ctdbd process ID", NULL
},
5938 { "disable", control_disable
, false, true,
5939 "disable a node", NULL
},
5940 { "enable", control_enable
, false, true,
5941 "enable a node", NULL
},
5942 { "stop", control_stop
, false, true,
5943 "stop a node", NULL
},
5944 { "continue", control_continue
, false, true,
5945 "continue a stopped node", NULL
},
5946 { "ban", control_ban
, false, true,
5947 "ban a node", "<bantime>"},
5948 { "unban", control_unban
, false, true,
5949 "unban a node", NULL
},
5950 { "shutdown", control_shutdown
, false, true,
5951 "shutdown ctdb daemon", NULL
},
5952 { "recover", control_recover
, false, true,
5953 "force recovery", NULL
},
5954 { "sync", control_ipreallocate
, false, true,
5955 "run ip reallocation (deprecated)", NULL
},
5956 { "ipreallocate", control_ipreallocate
, false, true,
5957 "run ip reallocation", NULL
},
5958 { "gratarp", control_gratarp
, false, true,
5959 "send a gratuitous arp", "<ip> <interface>" },
5960 { "tickle", control_tickle
, true, false,
5961 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5962 { "gettickles", control_gettickles
, false, true,
5963 "get the list of tickles", "<ip> [<port>]" },
5964 { "addtickle", control_addtickle
, false, true,
5965 "add a tickle", "<ip>:<port> <ip>:<port>" },
5966 { "deltickle", control_deltickle
, false, true,
5967 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5968 { "listnodes", control_listnodes
, true, true,
5969 "list nodes in the cluster", NULL
},
5970 { "reloadnodes", control_reloadnodes
, false, false,
5971 "reload the nodes file all nodes", NULL
},
5972 { "moveip", control_moveip
, false, false,
5973 "move an ip address to another node", "<ip> <node>" },
5974 { "addip", control_addip
, false, true,
5975 "add an ip address to a node", "<ip/mask> <iface>" },
5976 { "delip", control_delip
, false, true,
5977 "delete an ip address from a node", "<ip>" },
5978 { "backupdb", control_backupdb
, false, false,
5979 "backup a database into a file", "<dbname|dbid> <file>" },
5980 { "restoredb", control_restoredb
, false, false,
5981 "restore a database from a file", "<file> [dbname]" },
5982 { "dumpdbbackup", control_dumpdbbackup
, true, false,
5983 "dump database from a backup file", "<file>" },
5984 { "wipedb", control_wipedb
, false, false,
5985 "wipe the contents of a database.", "<dbname|dbid>"},
5986 { "recmaster", control_recmaster
, false, true,
5987 "show the pnn for the recovery master", NULL
},
5988 { "event", control_event
, true, false,
5989 "event and event script commands", NULL
},
5990 { "scriptstatus", control_scriptstatus
, true, false,
5991 "show event script status",
5992 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
5993 { "natgw", control_natgw
, false, false,
5994 "show natgw configuration", "leader|list|status" },
5995 { "getreclock", control_getreclock
, false, true,
5996 "get recovery lock file", NULL
},
5997 { "setlmasterrole", control_setlmasterrole
, false, true,
5998 "set LMASTER role", "on|off" },
5999 { "setrecmasterrole", control_setrecmasterrole
, false, true,
6000 "set RECMASTER role", "on|off"},
6001 { "setdbreadonly", control_setdbreadonly
, false, true,
6002 "enable readonly records", "<dbname|dbid>" },
6003 { "setdbsticky", control_setdbsticky
, false, true,
6004 "enable sticky records", "<dbname|dbid>"},
6005 { "pfetch", control_pfetch
, false, false,
6006 "fetch record from persistent database", "<dbname|dbid> <key>" },
6007 { "pstore", control_pstore
, false, false,
6008 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6009 { "pdelete", control_pdelete
, false, false,
6010 "delete record from persistent database", "<dbname|dbid> <key>" },
6011 { "ptrans", control_ptrans
, false, false,
6012 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6013 { "tfetch", control_tfetch
, false, true,
6014 "fetch a record", "<tdb-file> <key> [<file>]" },
6015 { "tstore", control_tstore
, false, true,
6016 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6017 { "readkey", control_readkey
, false, false,
6018 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6019 { "writekey", control_writekey
, false, false,
6020 "write value for a database key", "<dbname|dbid> <key> <value>" },
6021 { "deletekey", control_deletekey
, false, false,
6022 "delete a database key", "<dbname|dbid> <key>" },
6023 { "checktcpport", control_checktcpport
, true, false,
6024 "check if a service is bound to a specific tcp port or not", "<port>" },
6025 { "getdbseqnum", control_getdbseqnum
, false, false,
6026 "get database sequence number", "<dbname|dbid>" },
6027 { "nodestatus", control_nodestatus
, false, true,
6028 "show and return node status", "[all|<pnn-list>]" },
6029 { "dbstatistics", control_dbstatistics
, false, true,
6030 "show database statistics", "<dbname|dbid>" },
6031 { "reloadips", control_reloadips
, false, false,
6032 "reload the public addresses file", "[all|<pnn-list>]" },
6035 static const struct ctdb_cmd
*match_command(const char *command
)
6037 const struct ctdb_cmd
*cmd
;
6040 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6041 cmd
= &ctdb_commands
[i
];
6042 if (strlen(command
) == strlen(cmd
->name
) &&
6043 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6053 * Show usage message
6055 static void usage_full(void)
6059 poptPrintHelp(pc
, stdout
, 0);
6060 printf("\nCommands:\n");
6061 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6062 printf(" %-15s %-27s %s\n",
6063 ctdb_commands
[i
].name
,
6064 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6065 ctdb_commands
[i
].msg
);
6069 static void usage(const char *command
)
6071 const struct ctdb_cmd
*cmd
;
6073 if (command
== NULL
) {
6078 cmd
= match_command(command
);
6082 poptPrintUsage(pc
, stdout
, 0);
6083 printf("\nCommands:\n");
6084 printf(" %-15s %-27s %s\n",
6085 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6091 struct poptOption cmdline_options
[] = {
6094 .longName
= "debug",
6096 .argInfo
= POPT_ARG_STRING
,
6097 .arg
= &options
.debuglevelstr
,
6099 .descrip
= "debug level",
6102 .longName
= "timelimit",
6104 .argInfo
= POPT_ARG_INT
,
6105 .arg
= &options
.timelimit
,
6107 .descrip
= "timelimit (in seconds)",
6112 .argInfo
= POPT_ARG_INT
,
6113 .arg
= &options
.pnn
,
6115 .descrip
= "node specification - integer",
6120 .argInfo
= POPT_ARG_NONE
,
6121 .arg
= &options
.machinereadable
,
6123 .descrip
= "enable machine readable output",
6126 .longName
= "separator",
6128 .argInfo
= POPT_ARG_STRING
,
6129 .arg
= &options
.sep
,
6131 .descrip
= "specify separator for machine readable output",
6132 .argDescrip
= "CHAR",
6136 .argInfo
= POPT_ARG_NONE
,
6137 .arg
= &options
.machineparsable
,
6139 .descrip
= "enable machine parsable output with separator |",
6142 .longName
= "verbose",
6144 .argInfo
= POPT_ARG_NONE
,
6145 .arg
= &options
.verbose
,
6147 .descrip
= "enable verbose output",
6150 .longName
= "maxruntime",
6152 .argInfo
= POPT_ARG_INT
,
6153 .arg
= &options
.maxruntime
,
6155 .descrip
= "die if runtime exceeds this limit (in seconds)",
6160 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6163 TALLOC_CTX
*tmp_ctx
;
6164 struct ctdb_context
*ctdb
;
6165 const char *ctdb_socket
;
6168 uint64_t srvid_offset
;
6170 tmp_ctx
= talloc_new(NULL
);
6171 if (tmp_ctx
== NULL
) {
6172 fprintf(stderr
, "Memory allocation error\n");
6176 if (cmd
->without_daemon
) {
6177 if (options
.pnn
!= -1) {
6179 "Cannot specify node for command %s\n",
6184 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6185 talloc_free(tmp_ctx
);
6189 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6191 fprintf(stderr
, "Memory allocation error\n");
6195 ctdb
->ev
= tevent_context_init(ctdb
);
6196 if (ctdb
->ev
== NULL
) {
6197 fprintf(stderr
, "Failed to initialize tevent\n");
6201 ctdb_socket
= path_socket(ctdb
, "ctdbd");
6202 if (ctdb_socket
== NULL
) {
6203 fprintf(stderr
, "Memory allocation error\n");
6207 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6209 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6212 if (!find_node_xpnn(ctdb
, NULL
)) {
6213 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6218 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6219 srvid_offset
= getpid() & 0xFFFF;
6220 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6222 if (options
.pnn
!= -1) {
6223 status
= verify_pnn(ctdb
, options
.pnn
);
6228 ctdb
->cmd_pnn
= options
.pnn
;
6230 ctdb
->cmd_pnn
= ctdb
->pnn
;
6233 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6234 fprintf(stderr
, "Node cannot be specified for command %s\n",
6239 ctdb
->leader_pnn
= CTDB_UNKNOWN_PNN
;
6240 ret
= ctdb_client_set_message_handler(ctdb
->ev
,
6246 fprintf(stderr
, "Failed to setup leader handler\n");
6250 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6251 talloc_free(tmp_ctx
);
6255 talloc_free(tmp_ctx
);
6259 static void signal_handler(int sig
)
6261 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6264 static void alarm_handler(int sig
)
6266 /* Kill any child processes */
6267 signal(SIGTERM
, signal_handler
);
6273 int main(int argc
, const char *argv
[])
6276 const char **extra_argv
;
6278 const struct ctdb_cmd
*cmd
;
6279 const char *test_mode
;
6286 /* Set default options */
6287 options
.debuglevelstr
= NULL
;
6288 options
.timelimit
= 10;
6290 options
.maxruntime
= 0;
6293 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6294 POPT_CONTEXT_KEEP_FIRST
);
6295 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6296 fprintf(stderr
, "Invalid option %s: %s\n",
6297 poptBadOption(pc
, 0), poptStrerror(opt
));
6301 if (options
.maxruntime
== 0) {
6302 const char *ctdb_timeout
;
6304 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6305 if (ctdb_timeout
!= NULL
) {
6306 options
.maxruntime
= smb_strtoul(ctdb_timeout
,
6312 fprintf(stderr
, "Invalid value CTDB_TIMEOUT\n");
6316 options
.maxruntime
= 120;
6320 if (options
.machineparsable
) {
6321 options
.machinereadable
= 1;
6324 /* setup the remaining options for the commands */
6326 extra_argv
= poptGetArgs(pc
);
6329 while (extra_argv
[extra_argc
]) extra_argc
++;
6332 if (extra_argc
< 1) {
6336 cmd
= match_command(extra_argv
[0]);
6338 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6342 /* Enable logging */
6343 setup_logging("ctdb", DEBUG_STDERR
);
6344 ok
= debug_level_parse(options
.debuglevelstr
, &loglevel
);
6346 loglevel
= DEBUG_ERR
;
6348 debuglevel_set(loglevel
);
6350 /* Stop process group kill in alarm_handler() from killing tests */
6351 test_mode
= getenv("CTDB_TEST_MODE");
6352 if (test_mode
!= NULL
) {
6353 const char *have_setpgid
= getenv("CTDB_TOOL_SETPGID");
6354 if (have_setpgid
== NULL
) {
6356 setenv("CTDB_TOOL_SETPGID", "1", 1);
6360 signal(SIGALRM
, alarm_handler
);
6361 alarm(options
.maxruntime
);
6363 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6368 (void)poptFreeContext(pc
);