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_api.h"
44 #include "protocol/protocol_util.h"
45 #include "common/system_socket.h"
46 #include "client/client.h"
47 #include "client/client_sync.h"
49 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
51 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
52 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
55 const char *debuglevelstr
;
63 int printemptyrecords
;
70 static poptContext pc
;
73 struct tevent_context
*ev
;
74 struct ctdb_client_context
*client
;
75 struct ctdb_node_map
*nodemap
;
76 uint32_t pnn
, cmd_pnn
;
80 static void usage(const char *command
);
86 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
88 return (tv2
->tv_sec
- tv
->tv_sec
) +
89 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
92 static struct ctdb_node_and_flags
*get_node_by_pnn(
93 struct ctdb_node_map
*nodemap
,
98 for (i
=0; i
<nodemap
->num
; i
++) {
99 if (nodemap
->node
[i
].pnn
== pnn
) {
100 return &nodemap
->node
[i
];
106 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
108 static const struct {
112 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
113 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
114 { NODE_FLAGS_BANNED
, "BANNED" },
115 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
116 { NODE_FLAGS_DELETED
, "DELETED" },
117 { NODE_FLAGS_STOPPED
, "STOPPED" },
118 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
120 char *flags_str
= NULL
;
123 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
124 if (flags
& flag_names
[i
].flag
) {
125 if (flags_str
== NULL
) {
126 flags_str
= talloc_asprintf(mem_ctx
,
127 "%s", flag_names
[i
].name
);
129 flags_str
= talloc_asprintf_append(flags_str
,
130 "|%s", flag_names
[i
].name
);
132 if (flags_str
== NULL
) {
133 return "OUT-OF-MEMORY";
137 if (flags_str
== NULL
) {
144 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
151 * Get consistent nodemap information.
153 * If nodemap is already cached, use that. If not get it.
154 * If the current node is BANNED, then get nodemap from "better" node.
156 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
159 struct ctdb_node_map
*nodemap
;
160 struct ctdb_node_and_flags
*node
;
161 uint32_t current_node
;
165 TALLOC_FREE(ctdb
->nodemap
);
168 if (ctdb
->nodemap
!= NULL
) {
169 return ctdb
->nodemap
;
172 tmp_ctx
= talloc_new(ctdb
);
173 if (tmp_ctx
== NULL
) {
177 current_node
= ctdb
->pnn
;
179 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
180 current_node
, TIMEOUT(), &nodemap
);
182 fprintf(stderr
, "Failed to get nodemap from node %u\n",
187 node
= get_node_by_pnn(nodemap
, current_node
);
188 if (node
->flags
& NODE_FLAGS_BANNED
) {
191 current_node
= (current_node
+ 1) % nodemap
->num
;
192 node
= get_node_by_pnn(nodemap
, current_node
);
194 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
197 } while (current_node
!= ctdb
->pnn
);
199 if (current_node
== ctdb
->pnn
) {
200 /* Tried all nodes in the cluster */
201 fprintf(stderr
, "Warning: All nodes are banned.\n");
208 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
212 talloc_free(tmp_ctx
);
216 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
218 struct ctdb_node_map
*nodemap
;
226 nodemap
= get_nodemap(ctdb
, false);
227 if (nodemap
== NULL
) {
232 for (i
=0; i
<nodemap
->num
; i
++) {
233 if (nodemap
->node
[i
].pnn
== (uint32_t)pnn
) {
239 fprintf(stderr
, "Node %u does not exist\n", pnn
);
243 if (nodemap
->node
[i
].flags
&
244 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
245 fprintf(stderr
, "Node %u has status %s\n", pnn
,
246 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
253 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
254 struct ctdb_node_map
*nodemap
)
256 struct ctdb_node_map
*nodemap2
;
258 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
259 if (nodemap2
== NULL
) {
263 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
265 if (nodemap2
->node
== NULL
) {
266 talloc_free(nodemap2
);
274 * Get the number and the list of matching nodes
276 * nodestring := NULL | all | pnn,[pnn,...]
278 * If nodestring is NULL, use the current node.
280 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
281 const char *nodestring
,
282 struct ctdb_node_map
**out
)
284 struct ctdb_node_map
*nodemap
, *nodemap2
;
285 struct ctdb_node_and_flags
*node
;
288 nodemap
= get_nodemap(ctdb
, false);
289 if (nodemap
== NULL
) {
293 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
294 if (nodemap2
== NULL
) {
298 if (nodestring
== NULL
) {
299 for (i
=0; i
<nodemap
->num
; i
++) {
300 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
301 nodemap2
->node
[0] = nodemap
->node
[i
];
310 if (strcmp(nodestring
, "all") == 0) {
311 for (i
=0; i
<nodemap
->num
; i
++) {
312 nodemap2
->node
[i
] = nodemap
->node
[i
];
314 nodemap2
->num
= nodemap
->num
;
321 ns
= talloc_strdup(mem_ctx
, nodestring
);
326 tok
= strtok(ns
, ",");
327 while (tok
!= NULL
) {
330 pnn
= (uint32_t)smb_strtoul(tok
,
336 fprintf(stderr
, "Invalid node %s\n", tok
);
340 node
= get_node_by_pnn(nodemap
, pnn
);
342 fprintf(stderr
, "Node %u does not exist\n",
347 nodemap2
->node
[nodemap2
->num
] = *node
;
350 tok
= strtok(NULL
, ",");
359 /* Compare IP address */
360 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
364 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
368 switch (ip1
->sa
.sa_family
) {
370 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
371 sizeof(struct in_addr
)) == 0);
375 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
376 sizeof(struct in6_addr
)) == 0);
383 /* Append a node to a node map with given address and flags */
384 static bool node_map_add(struct ctdb_node_map
*nodemap
,
385 const char *nstr
, uint32_t flags
)
389 struct ctdb_node_and_flags
*n
;
392 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
394 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
399 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
400 struct ctdb_node_and_flags
, num
+1);
401 if (nodemap
->node
== NULL
) {
405 n
= &nodemap
->node
[num
];
410 nodemap
->num
= num
+1;
414 /* Read a nodes file into a node map */
415 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
421 struct ctdb_node_map
*nodemap
;
423 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
424 if (nodemap
== NULL
) {
428 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
433 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
437 for (i
=0; i
<nlines
; i
++) {
443 /* strip leading spaces */
444 while((*node
== ' ') || (*node
== '\t')) {
450 /* strip trailing spaces */
452 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
462 /* A "deleted" node is a node that is
463 commented out in the nodes file. This is
464 used instead of removing a line, which
465 would cause subsequent nodes to change
467 flags
= NODE_FLAGS_DELETED
;
468 node
= discard_const("0.0.0.0");
472 if (! node_map_add(nodemap
, node
, flags
)) {
474 TALLOC_FREE(nodemap
);
483 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
485 struct ctdb_node_map
*nodemap
;
486 const char *nodes_list
= NULL
;
488 const char *basedir
= getenv("CTDB_BASE");
489 if (basedir
== NULL
) {
490 basedir
= CTDB_ETCDIR
;
492 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
493 if (nodes_list
== NULL
) {
494 fprintf(stderr
, "Memory allocation error\n");
498 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
499 if (nodemap
== NULL
) {
500 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
508 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
509 struct ctdb_context
*ctdb
,
510 struct ctdb_dbid_map
*dbmap
,
513 struct ctdb_dbid
*db
= NULL
;
518 for (i
=0; i
<dbmap
->num
; i
++) {
519 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
520 ctdb
->pnn
, TIMEOUT(),
521 dbmap
->dbs
[i
].db_id
, &name
);
526 if (strcmp(db_name
, name
) == 0) {
527 talloc_free(discard_const(name
));
536 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
537 const char *db_arg
, uint32_t *db_id
,
538 const char **db_name
, uint8_t *db_flags
)
540 struct ctdb_dbid_map
*dbmap
;
541 struct ctdb_dbid
*db
= NULL
;
543 const char *name
= NULL
;
547 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
548 ctdb
->pnn
, TIMEOUT(), &dbmap
);
553 if (strncmp(db_arg
, "0x", 2) == 0) {
554 id
= smb_strtoul(db_arg
, NULL
, 0, &ret
, SMB_STR_STANDARD
);
558 for (i
=0; i
<dbmap
->num
; i
++) {
559 if (id
== dbmap
->dbs
[i
].db_id
) {
566 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
570 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
575 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
576 ctdb
->pnn
, TIMEOUT(), id
, &name
);
585 if (db_name
!= NULL
) {
586 *db_name
= talloc_strdup(mem_ctx
, name
);
588 if (db_flags
!= NULL
) {
589 *db_flags
= db
->flags
;
594 static int h2i(char h
)
596 if (h
>= 'a' && h
<= 'f') {
599 if (h
>= 'A' && h
<= 'F') {
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 data
.dptr
[i
] = h2i(str
[i
*2]) << 4 | h2i(str
[i
*2+1]);
631 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
637 if (strncmp(str
, "0x", 2) == 0) {
638 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
643 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
644 if (data
.dptr
== NULL
) {
654 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
655 const char *path
, int argc
, const char **argv
)
658 int save_errno
, status
, ret
;
659 const char **new_argv
;
662 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
663 if (new_argv
== NULL
) {
668 for (i
=0; i
<argc
; i
++) {
669 new_argv
[i
+1] = argv
[i
];
671 new_argv
[argc
+1] = NULL
;
676 talloc_free(new_argv
);
677 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
678 command
, path
, strerror(save_errno
));
683 ret
= execv(path
, discard_const(new_argv
));
687 /* Should not happen */
691 talloc_free(new_argv
);
693 ret
= waitpid(pid
, &status
, 0);
696 fprintf(stderr
, "waitpid() failed for %s - %s\n",
697 command
, strerror(save_errno
));
701 if (WIFEXITED(status
)) {
702 int pstatus
= WEXITSTATUS(status
);
703 if (WIFSIGNALED(status
)) {
704 fprintf(stderr
, "%s terminated with signal %d\n",
705 command
, WTERMSIG(status
));
707 } else if (pstatus
>= 64 && pstatus
< 255) {
708 fprintf(stderr
, "%s failed with error %d\n",
709 command
, pstatus
-64);
715 } else if (WIFSIGNALED(status
)) {
716 fprintf(stderr
, "%s terminated with signal %d\n",
717 command
, WTERMSIG(status
));
728 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
729 int argc
, const char **argv
)
731 printf("%s\n", SAMBA_VERSION_STRING
);
735 static bool partially_online(TALLOC_CTX
*mem_ctx
,
736 struct ctdb_context
*ctdb
,
737 struct ctdb_node_and_flags
*node
)
739 struct ctdb_iface_list
*iface_list
;
744 if (node
->flags
!= 0) {
748 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
749 node
->pnn
, TIMEOUT(), &iface_list
);
755 for (i
=0; i
< iface_list
->num
; i
++) {
756 if (iface_list
->iface
[i
].link_state
== 0) {
765 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
766 struct ctdb_context
*ctdb
,
767 struct ctdb_node_map
*nodemap
,
770 struct ctdb_node_and_flags
*node
;
773 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
777 "Disconnected", options
.sep
,
778 "Banned", options
.sep
,
779 "Disabled", options
.sep
,
780 "Unhealthy", options
.sep
,
781 "Stopped", options
.sep
,
782 "Inactive", options
.sep
,
783 "PartiallyOnline", options
.sep
,
784 "ThisNode", options
.sep
);
786 for (i
=0; i
<nodemap
->num
; i
++) {
787 node
= &nodemap
->node
[i
];
788 if (node
->flags
& NODE_FLAGS_DELETED
) {
792 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
794 node
->pnn
, options
.sep
,
795 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
797 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
798 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
799 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
801 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
802 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
803 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
804 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
805 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
810 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
811 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
814 struct ctdb_node_and_flags
*node
;
815 int num_deleted_nodes
= 0;
818 for (i
=0; i
<nodemap
->num
; i
++) {
819 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
825 if (num_deleted_nodes
== 0) {
826 printf("Number of nodes:%d\n", nodemap
->num
);
828 printf("Number of nodes:%d "
829 "(including %d deleted nodes)\n",
830 nodemap
->num
, num_deleted_nodes
);
834 for (i
=0; i
<nodemap
->num
; i
++) {
835 node
= &nodemap
->node
[i
];
836 if (node
->flags
& NODE_FLAGS_DELETED
) {
840 printf("pnn:%u %-16s %s%s\n",
842 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
843 partially_online(mem_ctx
, ctdb
, node
) ?
845 pretty_print_flags(mem_ctx
, node
->flags
),
846 node
->pnn
== mypnn
? " (THIS NODE)" : "");
850 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
851 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
852 struct ctdb_vnn_map
*vnnmap
, int recmode
,
857 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
859 if (vnnmap
->generation
== INVALID_GENERATION
) {
860 printf("Generation:INVALID\n");
862 printf("Generation:%u\n", vnnmap
->generation
);
864 printf("Size:%d\n", vnnmap
->size
);
865 for (i
=0; i
<vnnmap
->size
; i
++) {
866 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
869 printf("Recovery mode:%s (%d)\n",
870 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
872 printf("Recovery master:%d\n", recmaster
);
875 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
876 int argc
, const char **argv
)
878 struct ctdb_node_map
*nodemap
;
879 struct ctdb_vnn_map
*vnnmap
;
888 nodemap
= get_nodemap(ctdb
, false);
889 if (nodemap
== NULL
) {
893 if (options
.machinereadable
== 1) {
894 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
898 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
899 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
904 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
905 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
910 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
911 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
916 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
921 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
922 int argc
, const char **argv
)
924 struct ctdb_uptime
*uptime
;
925 int ret
, tmp
, days
, hours
, minutes
, seconds
;
927 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
928 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
933 printf("Current time of node %-4u : %s",
934 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
936 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
937 seconds
= tmp
% 60; tmp
/= 60;
938 minutes
= tmp
% 60; tmp
/= 60;
939 hours
= tmp
% 24; tmp
/= 24;
942 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
943 days
, hours
, minutes
, seconds
,
944 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
946 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
947 seconds
= tmp
% 60; tmp
/= 60;
948 minutes
= tmp
% 60; tmp
/= 60;
949 hours
= tmp
% 24; tmp
/= 24;
952 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
953 days
, hours
, minutes
, seconds
,
954 ctime(&uptime
->last_recovery_finished
.tv_sec
));
956 printf("Duration of last recovery/failover: %lf seconds\n",
957 timeval_delta(&uptime
->last_recovery_finished
,
958 &uptime
->last_recovery_started
));
963 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
964 int argc
, const char **argv
)
967 int ret
, num_clients
;
969 tv
= timeval_current();
970 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
971 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
976 printf("response from %u time=%.6f sec (%d clients)\n",
977 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
981 const char *runstate_to_string(enum ctdb_runstate runstate
);
982 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
984 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
985 int argc
, const char **argv
)
987 enum ctdb_runstate runstate
;
991 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
992 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
998 for (i
=0; i
<argc
; i
++) {
999 enum ctdb_runstate t
;
1002 t
= ctdb_runstate_from_string(argv
[i
]);
1003 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
1004 printf("Invalid run state (%s)\n", argv
[i
]);
1008 if (t
== runstate
) {
1015 printf("CTDB not in required run state (got %s)\n",
1016 ctdb_runstate_to_string(runstate
));
1020 printf("%s\n", ctdb_runstate_to_string(runstate
));
1024 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1025 int argc
, const char **argv
)
1027 struct ctdb_var_list
*tun_var_list
;
1036 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1037 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1040 "Failed to get list of variables from node %u\n",
1046 for (i
=0; i
<tun_var_list
->count
; i
++) {
1047 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1054 printf("No such tunable %s\n", argv
[0]);
1058 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1059 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1064 printf("%-26s = %u\n", argv
[0], value
);
1068 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1069 int argc
, const char **argv
)
1071 struct ctdb_var_list
*tun_var_list
;
1072 struct ctdb_tunable tunable
;
1081 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1082 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1085 "Failed to get list of variables from node %u\n",
1091 for (i
=0; i
<tun_var_list
->count
; i
++) {
1092 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1099 printf("No such tunable %s\n", argv
[0]);
1103 tunable
.name
= argv
[0];
1104 tunable
.value
= smb_strtoul(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1109 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1110 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1114 "Setting obsolete tunable variable '%s'\n",
1123 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1124 int argc
, const char **argv
)
1126 struct ctdb_var_list
*tun_var_list
;
1133 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1134 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1139 for (i
=0; i
<tun_var_list
->count
; i
++) {
1140 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1149 } stats_fields
[] = {
1150 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1151 STATISTICS_FIELD(num_clients
),
1152 STATISTICS_FIELD(frozen
),
1153 STATISTICS_FIELD(recovering
),
1154 STATISTICS_FIELD(num_recoveries
),
1155 STATISTICS_FIELD(client_packets_sent
),
1156 STATISTICS_FIELD(client_packets_recv
),
1157 STATISTICS_FIELD(node_packets_sent
),
1158 STATISTICS_FIELD(node_packets_recv
),
1159 STATISTICS_FIELD(keepalive_packets_sent
),
1160 STATISTICS_FIELD(keepalive_packets_recv
),
1161 STATISTICS_FIELD(node
.req_call
),
1162 STATISTICS_FIELD(node
.reply_call
),
1163 STATISTICS_FIELD(node
.req_dmaster
),
1164 STATISTICS_FIELD(node
.reply_dmaster
),
1165 STATISTICS_FIELD(node
.reply_error
),
1166 STATISTICS_FIELD(node
.req_message
),
1167 STATISTICS_FIELD(node
.req_control
),
1168 STATISTICS_FIELD(node
.reply_control
),
1169 STATISTICS_FIELD(node
.req_tunnel
),
1170 STATISTICS_FIELD(client
.req_call
),
1171 STATISTICS_FIELD(client
.req_message
),
1172 STATISTICS_FIELD(client
.req_control
),
1173 STATISTICS_FIELD(client
.req_tunnel
),
1174 STATISTICS_FIELD(timeouts
.call
),
1175 STATISTICS_FIELD(timeouts
.control
),
1176 STATISTICS_FIELD(timeouts
.traverse
),
1177 STATISTICS_FIELD(locks
.num_calls
),
1178 STATISTICS_FIELD(locks
.num_current
),
1179 STATISTICS_FIELD(locks
.num_pending
),
1180 STATISTICS_FIELD(locks
.num_failed
),
1181 STATISTICS_FIELD(total_calls
),
1182 STATISTICS_FIELD(pending_calls
),
1183 STATISTICS_FIELD(childwrite_calls
),
1184 STATISTICS_FIELD(pending_childwrite_calls
),
1185 STATISTICS_FIELD(memory_used
),
1186 STATISTICS_FIELD(max_hop_count
),
1187 STATISTICS_FIELD(total_ro_delegations
),
1188 STATISTICS_FIELD(total_ro_revokes
),
1191 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1193 static void print_statistics_machine(struct ctdb_statistics
*s
,
1199 printf("CTDB version%s", options
.sep
);
1200 printf("Current time of statistics%s", options
.sep
);
1201 printf("Statistics collected since%s", options
.sep
);
1202 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1203 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1205 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1206 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1207 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1208 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1210 printf("num_reclock_recd_latency%s", options
.sep
);
1211 printf("min_reclock_recd_latency%s", options
.sep
);
1212 printf("avg_reclock_recd_latency%s", options
.sep
);
1213 printf("max_reclock_recd_latency%s", options
.sep
);
1215 printf("num_call_latency%s", options
.sep
);
1216 printf("min_call_latency%s", options
.sep
);
1217 printf("avg_call_latency%s", options
.sep
);
1218 printf("max_call_latency%s", options
.sep
);
1220 printf("num_lockwait_latency%s", options
.sep
);
1221 printf("min_lockwait_latency%s", options
.sep
);
1222 printf("avg_lockwait_latency%s", options
.sep
);
1223 printf("max_lockwait_latency%s", options
.sep
);
1225 printf("num_childwrite_latency%s", options
.sep
);
1226 printf("min_childwrite_latency%s", options
.sep
);
1227 printf("avg_childwrite_latency%s", options
.sep
);
1228 printf("max_childwrite_latency%s", options
.sep
);
1232 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1233 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1234 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1235 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1237 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1240 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1241 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1242 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1243 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1245 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1246 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1247 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1248 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1250 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1251 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1252 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1253 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1255 printf("%u%s", s
->locks
.latency
.num
, options
.sep
);
1256 printf("%.6f%s", s
->locks
.latency
.min
, options
.sep
);
1257 printf("%.6f%s", LATENCY_AVG(s
->locks
.latency
), options
.sep
);
1258 printf("%.6f%s", s
->locks
.latency
.max
, options
.sep
);
1260 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1261 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1262 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1263 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1267 static void print_statistics(struct ctdb_statistics
*s
)
1269 int tmp
, days
, hours
, minutes
, seconds
;
1271 const char *prefix
= NULL
;
1274 tmp
= s
->statistics_current_time
.tv_sec
-
1275 s
->statistics_start_time
.tv_sec
;
1276 seconds
= tmp
% 60; tmp
/= 60;
1277 minutes
= tmp
% 60; tmp
/= 60;
1278 hours
= tmp
% 24; tmp
/= 24;
1281 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1282 printf("Current time of statistics : %s",
1283 ctime(&s
->statistics_current_time
.tv_sec
));
1284 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1285 days
, hours
, minutes
, seconds
,
1286 ctime(&s
->statistics_start_time
.tv_sec
));
1288 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1289 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1290 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1292 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1293 prefix
= stats_fields
[i
].name
;
1294 printf(" %*.*s\n", preflen
-1, preflen
-1,
1295 stats_fields
[i
].name
);
1300 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1301 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1302 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1305 printf(" hop_count_buckets:");
1306 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1307 printf(" %d", s
->hop_count_bucket
[i
]);
1310 printf(" lock_buckets:");
1311 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1312 printf(" %d", s
->locks
.buckets
[i
]);
1315 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1316 "locks_latency MIN/AVG/MAX",
1317 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1318 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1320 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1321 "reclock_ctdbd MIN/AVG/MAX",
1322 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1323 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1325 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1326 "reclock_recd MIN/AVG/MAX",
1327 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1328 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1330 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1331 "call_latency MIN/AVG/MAX",
1332 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1333 s
->call_latency
.max
, s
->call_latency
.num
);
1335 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1336 "childwrite_latency MIN/AVG/MAX",
1337 s
->childwrite_latency
.min
,
1338 LATENCY_AVG(s
->childwrite_latency
),
1339 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1342 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1343 int argc
, const char **argv
)
1345 struct ctdb_statistics
*stats
;
1349 usage("statistics");
1352 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1353 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1358 if (options
.machinereadable
) {
1359 print_statistics_machine(stats
, true);
1361 print_statistics(stats
);
1367 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1368 struct ctdb_context
*ctdb
,
1369 int argc
, const char **argv
)
1374 usage("statisticsreset");
1377 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1378 ctdb
->cmd_pnn
, TIMEOUT());
1386 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1387 int argc
, const char **argv
)
1389 struct ctdb_statistics_list
*slist
;
1390 int ret
, count
= 0, i
;
1391 bool show_header
= true;
1398 count
= atoi(argv
[0]);
1401 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1402 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1407 for (i
=0; i
<slist
->num
; i
++) {
1408 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1411 if (options
.machinereadable
== 1) {
1412 print_statistics_machine(&slist
->stats
[i
],
1414 show_header
= false;
1416 print_statistics(&slist
->stats
[i
]);
1418 if (count
> 0 && i
== count
) {
1426 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1428 const struct ctdb_public_ip
*ip_a
= a
;
1429 const struct ctdb_public_ip
*ip_b
= b
;
1431 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1434 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1435 struct ctdb_public_ip_list
*ips
,
1436 struct ctdb_public_ip_info
**ipinfo
,
1440 char *conf
, *avail
, *active
;
1442 if (options
.machinereadable
== 1) {
1443 printf("%s%s%s%s%s", options
.sep
,
1444 "Public IP", options
.sep
,
1445 "Node", options
.sep
);
1446 if (options
.verbose
== 1) {
1447 printf("%s%s%s%s%s%s\n",
1448 "ActiveInterfaces", options
.sep
,
1449 "AvailableInterfaces", options
.sep
,
1450 "ConfiguredInterfaces", options
.sep
);
1456 printf("Public IPs on ALL nodes\n");
1458 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1462 for (i
= 0; i
< ips
->num
; i
++) {
1464 if (options
.machinereadable
== 1) {
1465 printf("%s%s%s%d%s", options
.sep
,
1466 ctdb_sock_addr_to_string(
1467 mem_ctx
, &ips
->ip
[i
].addr
, false),
1469 (int)ips
->ip
[i
].pnn
, options
.sep
);
1471 printf("%s", ctdb_sock_addr_to_string(
1472 mem_ctx
, &ips
->ip
[i
].addr
, false));
1475 if (options
.verbose
== 0) {
1476 if (options
.machinereadable
== 1) {
1479 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1488 if (ipinfo
[i
] == NULL
) {
1492 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1493 struct ctdb_iface
*iface
;
1495 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1497 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1499 conf
= talloc_asprintf_append(
1500 conf
, ",%s", iface
->name
);
1503 if (ipinfo
[i
]->active_idx
== j
) {
1504 active
= iface
->name
;
1507 if (iface
->link_state
== 0) {
1511 if (avail
== NULL
) {
1512 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1514 avail
= talloc_asprintf_append(
1515 avail
, ",%s", iface
->name
);
1521 if (options
.machinereadable
== 1) {
1522 printf("%s%s%s%s%s%s\n",
1523 active
? active
: "", options
.sep
,
1524 avail
? avail
: "", options
.sep
,
1525 conf
? conf
: "", options
.sep
);
1527 printf(" node[%d] active[%s] available[%s]"
1528 " configured[%s]\n",
1529 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1530 avail
? avail
: "", conf
? conf
: "");
1535 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1536 size_t datalen
, void *private_data
)
1538 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1539 private_data
, struct ctdb_public_ip_list
);
1540 struct ctdb_public_ip
*ip
;
1542 ip
= (struct ctdb_public_ip
*)databuf
;
1543 ips
->ip
[ips
->num
] = *ip
;
1549 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1550 struct ctdb_public_ip_list
**out
)
1552 struct ctdb_node_map
*nodemap
;
1553 struct ctdb_public_ip_list
*ips
;
1554 struct db_hash_context
*ipdb
;
1559 nodemap
= get_nodemap(ctdb
, false);
1560 if (nodemap
== NULL
) {
1564 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1569 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1575 for (i
=0; i
<count
; i
++) {
1576 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1577 pnn_list
[i
], TIMEOUT(),
1583 for (j
=0; j
<ips
->num
; j
++) {
1584 struct ctdb_public_ip ip
;
1586 ip
.pnn
= ips
->ip
[j
].pnn
;
1587 ip
.addr
= ips
->ip
[j
].addr
;
1589 if (pnn_list
[i
] == ip
.pnn
) {
1590 /* Node claims IP is hosted on it, so
1591 * save that information
1593 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1595 (uint8_t *)&ip
, sizeof(ip
));
1600 /* Node thinks IP is hosted elsewhere,
1601 * so overwrite with CTDB_UNKNOWN_PNN
1602 * if there's no existing entry
1604 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1606 if (ret
== ENOENT
) {
1607 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1608 ret
= db_hash_add(ipdb
,
1609 (uint8_t *)&ip
.addr
,
1623 talloc_free(pnn_list
);
1625 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1630 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1635 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1636 if (ips
->ip
== NULL
) {
1640 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1645 if ((unsigned int)count
!= ips
->num
) {
1659 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1660 int argc
, const char **argv
)
1662 struct ctdb_public_ip_list
*ips
;
1663 struct ctdb_public_ip_info
**ipinfo
;
1666 bool do_all
= false;
1673 if (strcmp(argv
[0], "all") == 0) {
1681 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1683 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1684 ctdb
->cmd_pnn
, TIMEOUT(),
1691 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1692 ctdb_public_ip_cmp
);
1694 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1695 if (ipinfo
== NULL
) {
1699 for (i
=0; i
<ips
->num
; i
++) {
1702 pnn
= ips
->ip
[i
].pnn
;
1704 pnn
= ctdb
->cmd_pnn
;
1706 if (pnn
== CTDB_UNKNOWN_PNN
) {
1710 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1712 TIMEOUT(), &ips
->ip
[i
].addr
,
1719 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1723 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1724 int argc
, const char **argv
)
1726 struct ctdb_public_ip_info
*ipinfo
;
1727 ctdb_sock_addr addr
;
1735 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1737 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1741 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1742 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1746 printf("Node %u does not know about IP %s\n",
1747 ctdb
->cmd_pnn
, argv
[0]);
1752 printf("Public IP[%s] info on node %u\n",
1753 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1756 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1757 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1758 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1760 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1761 struct ctdb_iface
*iface
;
1763 iface
= &ipinfo
->ifaces
->iface
[i
];
1764 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1765 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1767 iface
->link_state
== 0 ? "down" : "up",
1769 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1775 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1776 int argc
, const char **argv
)
1778 struct ctdb_iface_list
*ifaces
;
1786 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1787 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1792 if (ifaces
->num
== 0) {
1793 printf("No interfaces configured on node %u\n",
1798 if (options
.machinereadable
) {
1799 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1800 "Name", options
.sep
,
1801 "LinkStatus", options
.sep
,
1802 "References", options
.sep
);
1804 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1807 for (i
=0; i
<ifaces
->num
; i
++) {
1808 if (options
.machinereadable
) {
1809 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1810 ifaces
->iface
[i
].name
, options
.sep
,
1811 ifaces
->iface
[i
].link_state
, options
.sep
,
1812 ifaces
->iface
[i
].references
, options
.sep
);
1814 printf("name:%s link:%s references:%u\n",
1815 ifaces
->iface
[i
].name
,
1816 ifaces
->iface
[i
].link_state
? "up" : "down",
1817 ifaces
->iface
[i
].references
);
1824 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1825 int argc
, const char **argv
)
1827 struct ctdb_iface_list
*ifaces
;
1828 struct ctdb_iface
*iface
;
1833 usage("setifacelink");
1836 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1837 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1841 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1842 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1845 "Failed to get interface information from node %u\n",
1851 for (i
=0; i
<ifaces
->num
; i
++) {
1852 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1853 iface
= &ifaces
->iface
[i
];
1858 if (iface
== NULL
) {
1859 printf("Interface %s not configured on node %u\n",
1860 argv
[0], ctdb
->cmd_pnn
);
1864 if (strcmp(argv
[1], "up") == 0) {
1865 iface
->link_state
= 1;
1866 } else if (strcmp(argv
[1], "down") == 0) {
1867 iface
->link_state
= 0;
1869 usage("setifacelink");
1873 iface
->references
= 0;
1875 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1876 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1884 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1885 struct ctdb_context
*ctdb
,
1886 int argc
, const char **argv
)
1893 if (argc
!= 1 && argc
!= 2) {
1894 usage("process-exists");
1897 pid
= atoi(argv
[0]);
1899 srvid
= smb_strtoull(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1906 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1907 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1909 struct ctdb_pid_srvid pid_srvid
;
1911 pid_srvid
.pid
= pid
;
1912 pid_srvid
.srvid
= srvid
;
1914 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
1915 ctdb
->client
, ctdb
->cmd_pnn
,
1916 TIMEOUT(), &pid_srvid
,
1925 printf("PID %d %s\n", pid
,
1926 (status
== 0 ? "exists" : "does not exist"));
1928 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
1929 (status
== 0 ? "exists" : "does not exist"));
1934 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1935 int argc
, const char **argv
)
1937 struct ctdb_dbid_map
*dbmap
;
1945 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1946 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1951 if (options
.machinereadable
== 1) {
1952 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1955 "Name", options
.sep
,
1956 "Path", options
.sep
,
1957 "Persistent", options
.sep
,
1958 "Sticky", options
.sep
,
1959 "Unhealthy", options
.sep
,
1960 "Readonly", options
.sep
,
1961 "Replicated", options
.sep
);
1963 printf("Number of databases:%d\n", dbmap
->num
);
1966 for (i
=0; i
<dbmap
->num
; i
++) {
1976 db_id
= dbmap
->dbs
[i
].db_id
;
1978 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1979 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1985 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1986 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1992 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1993 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1999 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
2000 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
2001 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
2002 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
2004 if (options
.machinereadable
== 1) {
2005 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2010 !! (persistent
), options
.sep
,
2011 !! (sticky
), options
.sep
,
2012 !! (health
), options
.sep
,
2013 !! (readonly
), options
.sep
,
2014 !! (replicated
), options
.sep
);
2016 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2018 persistent
? " PERSISTENT" : "",
2019 sticky
? " STICKY" : "",
2020 readonly
? " READONLY" : "",
2021 replicated
? " REPLICATED" : "",
2022 health
? " UNHEALTHY" : "");
2025 talloc_free(discard_const(name
));
2026 talloc_free(discard_const(path
));
2027 talloc_free(discard_const(health
));
2033 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2034 int argc
, const char **argv
)
2037 const char *db_name
, *db_path
, *db_health
;
2042 usage("getdbstatus");
2045 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2049 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2050 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2056 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2057 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2063 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2064 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2065 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2066 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2067 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2068 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2069 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2073 struct dump_record_state
{
2077 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2079 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2083 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2084 for (i
=0; i
<val
.dsize
; i
++) {
2085 if (ISASCII(val
.dptr
[i
])) {
2086 fprintf(stdout
, "%c", val
.dptr
[i
]);
2088 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2091 fprintf(stdout
, "\"\n");
2094 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2096 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2097 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2098 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2099 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2100 fprintf(stdout
, " MIGRATED_WITH_DATA");
2102 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2103 fprintf(stdout
, " VACUUM_MIGRATED");
2105 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2106 fprintf(stdout
, " AUTOMATIC");
2108 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2109 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2111 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2112 fprintf(stdout
, " RO_HAVE_READONLY");
2114 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2115 fprintf(stdout
, " RO_REVOKING_READONLY");
2117 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2118 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2120 fprintf(stdout
, "\n");
2124 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2125 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2127 struct dump_record_state
*state
=
2128 (struct dump_record_state
*)private_data
;
2132 dump_tdb_data("key", key
);
2133 dump_ltdb_header(header
);
2134 dump_tdb_data("data", data
);
2135 fprintf(stdout
, "\n");
2140 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2141 int argc
, const char **argv
)
2143 struct ctdb_db_context
*db
;
2144 const char *db_name
;
2147 struct dump_record_state state
;
2154 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2158 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2161 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2167 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2168 ctdb
->cmd_pnn
, TIMEOUT(),
2169 dump_record
, &state
);
2171 printf("Dumped %u records\n", state
.count
);
2176 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2177 int argc
, const char **argv
)
2179 struct ctdb_db_context
*db
;
2180 const char *db_name
;
2183 struct dump_record_state state
;
2190 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2194 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2197 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2202 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2204 printf("Dumped %u record(s)\n", state
.count
);
2209 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2210 struct ctdb_context
*ctdb
,
2211 int argc
, const char **argv
)
2217 usage("getcapabilities");
2220 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2221 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2226 if (options
.machinereadable
== 1) {
2227 printf("%s%s%s%s%s\n",
2229 "RECMASTER", options
.sep
,
2230 "LMASTER", options
.sep
);
2231 printf("%s%d%s%d%s\n", options
.sep
,
2232 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2233 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2235 printf("RECMASTER: %s\n",
2236 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2237 printf("LMASTER: %s\n",
2238 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2244 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2245 int argc
, const char **argv
)
2247 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2251 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2252 int argc
, const char **argv
)
2254 char *t
, *lvs_helper
= NULL
;
2260 t
= getenv("CTDB_LVS_HELPER");
2262 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2264 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2265 CTDB_HELPER_BINDIR
);
2268 if (lvs_helper
== NULL
) {
2269 fprintf(stderr
, "Unable to set LVS helper\n");
2273 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2276 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2277 int argc
, const char **argv
)
2287 found
= debug_level_parse(argv
[0], &log_level
);
2290 "Invalid debug level '%s'. Valid levels are:\n",
2292 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2296 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2297 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2305 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2306 int argc
, const char **argv
)
2309 const char *log_str
;
2316 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2317 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2322 log_str
= debug_level_to_string(loglevel
);
2323 printf("%s\n", log_str
);
2328 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2329 int argc
, const char **argv
)
2331 const char *db_name
;
2332 uint8_t db_flags
= 0;
2335 if (argc
< 1 || argc
> 2) {
2341 if (strcmp(argv
[1], "persistent") == 0) {
2342 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2343 } else if (strcmp(argv
[1], "readonly") == 0) {
2344 db_flags
= CTDB_DB_FLAGS_READONLY
;
2345 } else if (strcmp(argv
[1], "sticky") == 0) {
2346 db_flags
= CTDB_DB_FLAGS_STICKY
;
2347 } else if (strcmp(argv
[1], "replicated") == 0) {
2348 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2354 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2363 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2364 int argc
, const char **argv
)
2366 const char *db_name
;
2369 struct ctdb_node_map
*nodemap
;
2378 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2379 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2384 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2385 fprintf(stderr
, "Database cannot be detached"
2386 " when recovery is active\n");
2390 nodemap
= get_nodemap(ctdb
, false);
2391 if (nodemap
== NULL
) {
2395 for (j
=0; j
<nodemap
->num
; j
++) {
2398 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DISCONNECTED
) {
2401 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DELETED
) {
2404 if (nodemap
->node
[j
].flags
& NODE_FLAGS_INACTIVE
) {
2405 fprintf(stderr
, "Database cannot be detached on"
2406 " inactive (stopped or banned) node %u\n",
2407 nodemap
->node
[j
].pnn
);
2411 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2412 nodemap
->node
[j
].pnn
, TIMEOUT(),
2413 "AllowClientDBAttach", &value
);
2416 "Unable to get tunable AllowClientDBAttach"
2417 " from node %u\n", nodemap
->node
[j
].pnn
);
2423 "Database access is still active on node %u."
2424 " Set AllowclientDBAttach=0 on all nodes.\n",
2425 nodemap
->node
[j
].pnn
);
2431 for (i
=0; i
<argc
; i
++) {
2432 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2438 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2440 "Only volatile databases can be detached\n");
2444 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2446 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2454 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2455 int argc
, const char **argv
)
2457 const char *mem_str
;
2461 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2462 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2467 n
= write(1, mem_str
, strlen(mem_str
));
2468 if (n
< 0 || (size_t)n
!= strlen(mem_str
)) {
2469 fprintf(stderr
, "Failed to write talloc summary\n");
2476 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2478 bool *done
= (bool *)private_data
;
2482 len
= strnlen((const char *)data
.dptr
, data
.dsize
);
2483 n
= write(1, data
.dptr
, len
);
2484 if (n
< 0 || (size_t)n
!= len
) {
2485 fprintf(stderr
, "Failed to write talloc summary\n");
2491 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2492 int argc
, const char **argv
)
2494 struct ctdb_srvid_message msg
= { 0 };
2498 msg
.pnn
= ctdb
->pnn
;
2499 msg
.srvid
= next_srvid(ctdb
);
2501 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2502 msg
.srvid
, dump_memory
, &done
);
2507 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2508 ctdb
->cmd_pnn
, &msg
);
2513 ctdb_client_wait(ctdb
->ev
, &done
);
2517 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2518 int argc
, const char **argv
)
2523 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2524 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2529 printf("%u\n", pid
);
2533 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2534 const char *desc
, uint32_t flag
, bool set_flag
)
2536 struct ctdb_node_map
*nodemap
;
2539 nodemap
= get_nodemap(ctdb
, false);
2540 if (nodemap
== NULL
) {
2544 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2545 if (set_flag
== flag_is_set
) {
2547 fprintf(stderr
, "Node %u is already %s\n",
2548 ctdb
->cmd_pnn
, desc
);
2550 fprintf(stderr
, "Node %u is not %s\n",
2551 ctdb
->cmd_pnn
, desc
);
2559 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2560 uint32_t flag
, bool set_flag
)
2562 struct ctdb_node_map
*nodemap
;
2566 nodemap
= get_nodemap(ctdb
, true);
2567 if (nodemap
== NULL
) {
2569 "Failed to get nodemap, trying again\n");
2574 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2575 if (flag_is_set
== set_flag
) {
2583 static int ctdb_ctrl_modflags(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
2584 struct ctdb_client_context
*client
,
2585 uint32_t destnode
, struct timeval timeout
,
2586 uint32_t set
, uint32_t clear
)
2588 struct ctdb_node_map
*nodemap
;
2589 struct ctdb_node_flag_change flag_change
;
2590 struct ctdb_req_control request
;
2594 ret
= ctdb_ctrl_get_nodemap(mem_ctx
, ev
, client
, destnode
,
2595 tevent_timeval_zero(), &nodemap
);
2600 flag_change
.pnn
= destnode
;
2601 flag_change
.old_flags
= nodemap
->node
[destnode
].flags
;
2602 flag_change
.new_flags
= flag_change
.old_flags
| set
;
2603 flag_change
.new_flags
&= ~clear
;
2605 count
= list_of_connected_nodes(nodemap
, -1, mem_ctx
, &pnn_list
);
2610 ctdb_req_control_modify_flags(&request
, &flag_change
);
2611 ret
= ctdb_client_control_multi(mem_ctx
, ev
, client
, pnn_list
, count
,
2612 tevent_timeval_zero(), &request
,
2617 struct ipreallocate_state
{
2622 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2625 struct ipreallocate_state
*state
=
2626 (struct ipreallocate_state
*)private_data
;
2628 if (data
.dsize
!= sizeof(int)) {
2633 state
->status
= *(int *)data
.dptr
;
2637 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2639 struct ctdb_srvid_message msg
= { 0 };
2640 struct ipreallocate_state state
;
2643 msg
.pnn
= ctdb
->pnn
;
2644 msg
.srvid
= next_srvid(ctdb
);
2647 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2649 ipreallocate_handler
, &state
);
2655 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2657 CTDB_BROADCAST_CONNECTED
,
2663 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2669 if (state
.status
>= 0) {
2678 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2683 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2684 int argc
, const char **argv
)
2692 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2693 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2698 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2699 ctdb
->cmd_pnn
, TIMEOUT(),
2700 NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2703 "Failed to set DISABLED flag on node %u\n",
2708 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2709 return ipreallocate(mem_ctx
, ctdb
);
2712 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2713 int argc
, const char **argv
)
2721 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2722 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2727 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2728 ctdb
->cmd_pnn
, TIMEOUT(),
2729 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2731 fprintf(stderr
, "Failed to reset DISABLED flag on node %u\n",
2736 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2737 return ipreallocate(mem_ctx
, ctdb
);
2740 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2741 int argc
, const char **argv
)
2749 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2750 NODE_FLAGS_STOPPED
, true);
2755 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2756 ctdb
->cmd_pnn
, TIMEOUT());
2758 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2762 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2763 return ipreallocate(mem_ctx
, ctdb
);
2766 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2767 int argc
, const char **argv
)
2775 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2776 NODE_FLAGS_STOPPED
, false);
2781 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2782 ctdb
->cmd_pnn
, TIMEOUT());
2784 fprintf(stderr
, "Failed to continue stopped node %u\n",
2789 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2790 return ipreallocate(mem_ctx
, ctdb
);
2793 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2794 int argc
, const char **argv
)
2796 struct ctdb_ban_state ban_state
;
2803 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2804 NODE_FLAGS_BANNED
, true);
2809 ban_state
.pnn
= ctdb
->cmd_pnn
;
2810 ban_state
.time
= smb_strtoul(argv
[0], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2815 if (ban_state
.time
== 0) {
2816 fprintf(stderr
, "Ban time cannot be zero\n");
2820 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2821 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2823 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2827 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2828 return ipreallocate(mem_ctx
, ctdb
);
2832 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2833 int argc
, const char **argv
)
2835 struct ctdb_ban_state ban_state
;
2842 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2843 NODE_FLAGS_BANNED
, false);
2848 ban_state
.pnn
= ctdb
->cmd_pnn
;
2851 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2852 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2854 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2858 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2859 return ipreallocate(mem_ctx
, ctdb
);
2863 static void wait_for_shutdown(void *private_data
)
2865 bool *done
= (bool *)private_data
;
2870 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2871 int argc
, const char **argv
)
2880 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2881 ctdb_client_set_disconnect_callback(ctdb
->client
,
2886 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2887 ctdb
->cmd_pnn
, TIMEOUT());
2889 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2893 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2894 ctdb_client_wait(ctdb
->ev
, &done
);
2900 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2901 uint32_t *generation
)
2905 struct ctdb_vnn_map
*vnnmap
;
2909 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2910 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2912 fprintf(stderr
, "Failed to find recovery master\n");
2916 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2917 recmaster
, TIMEOUT(), &recmode
);
2919 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2924 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2929 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2930 recmaster
, TIMEOUT(), &vnnmap
);
2932 fprintf(stderr
, "Failed to get generation from node %u\n",
2937 if (vnnmap
->generation
== INVALID_GENERATION
) {
2938 talloc_free(vnnmap
);
2943 *generation
= vnnmap
->generation
;
2944 talloc_free(vnnmap
);
2949 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2950 int argc
, const char **argv
)
2952 uint32_t generation
, next_generation
;
2959 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2964 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2965 ctdb
->cmd_pnn
, TIMEOUT(),
2966 CTDB_RECOVERY_ACTIVE
);
2968 fprintf(stderr
, "Failed to set recovery mode active\n");
2973 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2976 "Failed to confirm end of recovery\n");
2980 if (next_generation
!= generation
) {
2990 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2991 int argc
, const char **argv
)
2994 usage("ipreallocate");
2997 return ipreallocate(mem_ctx
, ctdb
);
3000 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3001 int argc
, const char **argv
)
3003 struct ctdb_addr_info addr_info
;
3010 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
3012 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3015 addr_info
.iface
= argv
[1];
3017 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3018 ctdb
->cmd_pnn
, TIMEOUT(),
3021 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3029 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3030 int argc
, const char **argv
)
3032 ctdb_sock_addr src
, dst
;
3035 if (argc
!= 0 && argc
!= 2) {
3040 struct ctdb_connection_list
*clist
;
3042 unsigned int num_failed
;
3044 /* Client first but the src/dst logic is confused */
3045 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3051 for (i
= 0; i
< clist
->num
; i
++) {
3052 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3053 &clist
->conn
[i
].dst
,
3062 if (num_failed
> 0) {
3063 fprintf(stderr
, "Failed to send %d tickles\n",
3072 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3074 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3078 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3080 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3084 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3086 fprintf(stderr
, "Failed to send tickle ack\n");
3093 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3094 int argc
, const char **argv
)
3096 ctdb_sock_addr addr
;
3097 struct ctdb_tickle_list
*tickles
;
3102 if (argc
< 1 || argc
> 2) {
3103 usage("gettickles");
3107 port
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3113 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3115 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3118 ctdb_sock_addr_set_port(&addr
, port
);
3120 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3121 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3124 fprintf(stderr
, "Failed to get list of connections\n");
3128 if (options
.machinereadable
) {
3129 printf("%s%s%s%s%s%s%s%s%s\n",
3131 "Source IP", options
.sep
,
3132 "Port", options
.sep
,
3133 "Destiation IP", options
.sep
,
3134 "Port", options
.sep
);
3135 for (i
=0; i
<tickles
->num
; i
++) {
3136 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3137 ctdb_sock_addr_to_string(
3138 mem_ctx
, &tickles
->conn
[i
].src
, false),
3140 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3142 ctdb_sock_addr_to_string(
3143 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3145 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3149 printf("Connections for IP: %s\n",
3150 ctdb_sock_addr_to_string(mem_ctx
,
3151 &tickles
->addr
, false));
3152 printf("Num connections: %u\n", tickles
->num
);
3153 for (i
=0; i
<tickles
->num
; i
++) {
3154 printf("SRC: %s DST: %s\n",
3155 ctdb_sock_addr_to_string(
3156 mem_ctx
, &tickles
->conn
[i
].src
, true),
3157 ctdb_sock_addr_to_string(
3158 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3162 talloc_free(tickles
);
3166 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3167 struct ctdb_connection
*conn
);
3169 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3171 struct process_clist_state
{
3172 struct ctdb_connection_list
*clist
;
3174 unsigned int num_failed
, num_total
;
3175 clist_reply_func reply_func
;
3178 static void process_clist_done(struct tevent_req
*subreq
);
3180 static struct tevent_req
*process_clist_send(
3181 TALLOC_CTX
*mem_ctx
,
3182 struct ctdb_context
*ctdb
,
3183 struct ctdb_connection_list
*clist
,
3184 clist_request_func request_func
,
3185 clist_reply_func reply_func
)
3187 struct tevent_req
*req
, *subreq
;
3188 struct process_clist_state
*state
;
3189 struct ctdb_req_control request
;
3192 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3197 state
->clist
= clist
;
3198 state
->reply_func
= reply_func
;
3200 for (i
= 0; i
< clist
->num
; i
++) {
3201 request_func(&request
, &clist
->conn
[i
]);
3202 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3203 ctdb
->client
, ctdb
->cmd_pnn
,
3204 TIMEOUT(), &request
);
3205 if (tevent_req_nomem(subreq
, req
)) {
3206 return tevent_req_post(req
, ctdb
->ev
);
3208 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3214 static void process_clist_done(struct tevent_req
*subreq
)
3216 struct tevent_req
*req
= tevent_req_callback_data(
3217 subreq
, struct tevent_req
);
3218 struct process_clist_state
*state
= tevent_req_data(
3219 req
, struct process_clist_state
);
3220 struct ctdb_reply_control
*reply
;
3224 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3225 TALLOC_FREE(subreq
);
3227 state
->num_failed
+= 1;
3231 ret
= state
->reply_func(reply
);
3233 state
->num_failed
+= 1;
3238 state
->num_total
+= 1;
3239 if (state
->num_total
== state
->clist
->num
) {
3240 tevent_req_done(req
);
3244 static int process_clist_recv(struct tevent_req
*req
)
3246 struct process_clist_state
*state
= tevent_req_data(
3247 req
, struct process_clist_state
);
3249 return state
->num_failed
;
3252 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3253 int argc
, const char **argv
)
3255 struct ctdb_connection conn
;
3258 if (argc
!= 0 && argc
!= 2) {
3263 struct ctdb_connection_list
*clist
;
3264 struct tevent_req
*req
;
3266 /* Client first but the src/dst logic is confused */
3267 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3271 if (clist
->num
== 0) {
3275 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3276 ctdb_req_control_tcp_add_delayed_update
,
3277 ctdb_reply_control_tcp_add_delayed_update
);
3283 tevent_req_poll(req
, ctdb
->ev
);
3286 ret
= process_clist_recv(req
);
3288 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3295 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3297 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3300 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3302 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3306 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3307 ctdb
->client
, ctdb
->cmd_pnn
,
3310 fprintf(stderr
, "Failed to register connection\n");
3317 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3318 int argc
, const char **argv
)
3320 struct ctdb_connection conn
;
3323 if (argc
!= 0 && argc
!= 2) {
3328 struct ctdb_connection_list
*clist
;
3329 struct tevent_req
*req
;
3331 /* Client first but the src/dst logic is confused */
3332 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3336 if (clist
->num
== 0) {
3340 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3341 ctdb_req_control_tcp_remove
,
3342 ctdb_reply_control_tcp_remove
);
3348 tevent_req_poll(req
, ctdb
->ev
);
3351 ret
= process_clist_recv(req
);
3353 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3360 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3362 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3365 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3367 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3371 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3372 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3374 fprintf(stderr
, "Failed to unregister connection\n");
3381 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3382 int argc
, const char **argv
)
3384 struct ctdb_node_map
*nodemap
;
3391 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3392 if (nodemap
== NULL
) {
3396 for (i
=0; i
<nodemap
->num
; i
++) {
3397 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3401 if (options
.machinereadable
) {
3402 printf("%s%u%s%s%s\n", options
.sep
,
3403 nodemap
->node
[i
].pnn
, options
.sep
,
3404 ctdb_sock_addr_to_string(
3405 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3409 ctdb_sock_addr_to_string(
3410 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3417 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3418 struct ctdb_node_map
*nodemap2
)
3422 if (nodemap1
->num
!= nodemap2
->num
) {
3426 for (i
=0; i
<nodemap1
->num
; i
++) {
3427 struct ctdb_node_and_flags
*n1
, *n2
;
3429 n1
= &nodemap1
->node
[i
];
3430 n2
= &nodemap2
->node
[i
];
3432 if ((n1
->pnn
!= n2
->pnn
) ||
3433 (n1
->flags
!= n2
->flags
) ||
3434 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3442 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3443 struct ctdb_node_map
*nm
,
3444 struct ctdb_node_map
*fnm
,
3448 bool check_failed
= false;
3452 for (i
=0; i
<nm
->num
; i
++) {
3453 if (i
>= fnm
->num
) {
3455 "Node %u (%s) missing from nodes file\n",
3457 ctdb_sock_addr_to_string(
3458 mem_ctx
, &nm
->node
[i
].addr
, false));
3459 check_failed
= true;
3462 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3463 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3464 /* Node remains deleted */
3468 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3469 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3470 /* Node not newly nor previously deleted */
3471 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3472 &fnm
->node
[i
].addr
)) {
3474 "Node %u has changed IP address"
3475 " (was %s, now %s)\n",
3477 ctdb_sock_addr_to_string(
3479 &nm
->node
[i
].addr
, false),
3480 ctdb_sock_addr_to_string(
3482 &fnm
->node
[i
].addr
, false));
3483 check_failed
= true;
3485 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3487 "WARNING: Node %u is disconnected."
3488 " You MUST fix this node manually!\n",
3495 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3496 /* Node is being deleted */
3497 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3499 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3501 "ERROR: Node %u is still connected\n",
3503 check_failed
= true;
3508 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3509 /* Node was previously deleted */
3510 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3517 "ERROR: Nodes will not be reloaded due to previous error\n");
3521 /* Leftover nodes in file are NEW */
3522 for (; i
< fnm
->num
; i
++) {
3523 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3530 struct disable_recoveries_state
{
3532 unsigned int node_count
;
3538 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3541 struct disable_recoveries_state
*state
=
3542 (struct disable_recoveries_state
*)private_data
;
3546 if (data
.dsize
!= sizeof(int)) {
3551 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3552 ret
= *(int *)data
.dptr
;
3554 state
->status
= ret
;
3558 for (i
=0; i
<state
->node_count
; i
++) {
3559 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
3560 state
->reply
[i
] = true;
3566 for (i
=0; i
<state
->node_count
; i
++) {
3567 if (! state
->reply
[i
]) {
3568 state
->done
= false;
3574 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3575 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3577 struct ctdb_disable_message disable
= { 0 };
3578 struct disable_recoveries_state state
;
3581 disable
.pnn
= ctdb
->pnn
;
3582 disable
.srvid
= next_srvid(ctdb
);
3583 disable
.timeout
= timeout
;
3585 state
.pnn_list
= pnn_list
;
3586 state
.node_count
= count
;
3589 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3590 if (state
.reply
== NULL
) {
3594 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3596 disable_recoveries_handler
,
3602 for (i
=0; i
<count
; i
++) {
3603 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3612 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3614 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3616 ret
= (state
.status
>= 0 ? 0 : 1);
3620 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3621 disable
.srvid
, &state
);
3625 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3626 int argc
, const char **argv
)
3628 struct ctdb_node_map
*nodemap
= NULL
;
3629 struct ctdb_node_map
*file_nodemap
;
3630 struct ctdb_node_map
*remote_nodemap
;
3631 struct ctdb_req_control request
;
3632 struct ctdb_reply_control
**reply
;
3639 nodemap
= get_nodemap(ctdb
, false);
3640 if (nodemap
== NULL
) {
3644 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3645 if (file_nodemap
== NULL
) {
3649 for (i
=0; i
<nodemap
->num
; i
++) {
3650 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3654 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3655 nodemap
->node
[i
].pnn
, TIMEOUT(),
3659 "ERROR: Failed to get nodes file from node %u\n",
3660 nodemap
->node
[i
].pnn
);
3664 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3666 "ERROR: Nodes file on node %u differs"
3667 " from current node (%u)\n",
3668 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3673 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3679 fprintf(stderr
, "No change in nodes file,"
3680 " skipping unnecessary reload\n");
3684 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3685 mem_ctx
, &pnn_list
);
3687 fprintf(stderr
, "Memory allocation error\n");
3691 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3694 fprintf(stderr
, "Failed to disable recoveries\n");
3698 ctdb_req_control_reload_nodes_file(&request
);
3699 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3700 pnn_list
, count
, TIMEOUT(),
3701 &request
, NULL
, &reply
);
3703 bool failed
= false;
3706 for (j
=0; j
<count
; j
++) {
3707 ret
= ctdb_reply_control_reload_nodes_file(reply
[j
]);
3710 "Node %u failed to reload nodes\n",
3717 "You MUST fix failed nodes manually!\n");
3721 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3723 fprintf(stderr
, "Failed to enable recoveries\n");
3730 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3731 ctdb_sock_addr
*addr
, uint32_t pnn
)
3733 struct ctdb_public_ip_list
*pubip_list
;
3734 struct ctdb_public_ip pubip
;
3735 struct ctdb_node_map
*nodemap
;
3736 struct ctdb_req_control request
;
3741 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3742 CTDB_BROADCAST_CONNECTED
,
3743 2*options
.timelimit
);
3745 fprintf(stderr
, "Failed to disable IP check\n");
3749 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3750 pnn
, TIMEOUT(), false, &pubip_list
);
3752 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3757 for (i
=0; i
<pubip_list
->num
; i
++) {
3758 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3763 if (i
== pubip_list
->num
) {
3764 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3765 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3769 nodemap
= get_nodemap(ctdb
, false);
3770 if (nodemap
== NULL
) {
3774 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3776 fprintf(stderr
, "Memory allocation error\n");
3782 ctdb_req_control_release_ip(&request
, &pubip
);
3784 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3785 pnn_list
, count
, TIMEOUT(),
3786 &request
, NULL
, NULL
);
3788 fprintf(stderr
, "Failed to release IP on nodes\n");
3792 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3793 pnn
, TIMEOUT(), &pubip
);
3795 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3802 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3803 int argc
, const char **argv
)
3805 ctdb_sock_addr addr
;
3814 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3816 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3820 pnn
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3821 if (pnn
== CTDB_UNKNOWN_PNN
|| ret
!= 0) {
3822 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3826 while (retries
< 5) {
3827 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3837 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3845 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3850 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3851 CTDB_BROADCAST_CONNECTED
, pnn
);
3854 "Failed to ask recovery master to distribute IPs\n");
3861 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3862 int argc
, const char **argv
)
3864 ctdb_sock_addr addr
;
3865 struct ctdb_public_ip_list
*pubip_list
;
3866 struct ctdb_addr_info addr_info
;
3867 unsigned int mask
, i
;
3868 int ret
, retries
= 0;
3874 ret
= ctdb_sock_addr_mask_from_string(argv
[0], &addr
, &mask
);
3876 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3880 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3881 ctdb
->cmd_pnn
, TIMEOUT(),
3882 false, &pubip_list
);
3884 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3889 for (i
=0; i
<pubip_list
->num
; i
++) {
3890 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3891 fprintf(stderr
, "Node already knows about IP %s\n",
3892 ctdb_sock_addr_to_string(mem_ctx
,
3898 addr_info
.addr
= addr
;
3899 addr_info
.mask
= mask
;
3900 addr_info
.iface
= argv
[1];
3902 while (retries
< 5) {
3903 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3904 ctdb
->cmd_pnn
, TIMEOUT(),
3915 fprintf(stderr
, "Failed to add public IP to node %u."
3916 " Giving up\n", ctdb
->cmd_pnn
);
3920 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3928 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3929 int argc
, const char **argv
)
3931 ctdb_sock_addr addr
;
3932 struct ctdb_public_ip_list
*pubip_list
;
3933 struct ctdb_addr_info addr_info
;
3941 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3943 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3947 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3948 ctdb
->cmd_pnn
, TIMEOUT(),
3949 false, &pubip_list
);
3951 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3956 for (i
=0; i
<pubip_list
->num
; i
++) {
3957 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3962 if (i
== pubip_list
->num
) {
3963 fprintf(stderr
, "Node does not know about IP address %s\n",
3964 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
3968 addr_info
.addr
= addr
;
3970 addr_info
.iface
= NULL
;
3972 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3973 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
3975 fprintf(stderr
, "Failed to delete public IP from node %u\n",
3983 #define DB_VERSION 3
3984 #define MAX_DB_NAME 64
3985 #define MAX_REC_BUFFER_SIZE (100*1000)
3988 unsigned long version
;
3990 unsigned long flags
;
3993 char name
[MAX_DB_NAME
];
3996 struct backup_state
{
3997 TALLOC_CTX
*mem_ctx
;
3998 struct ctdb_rec_buffer
*recbuf
;
4001 unsigned int nbuf
, nrec
;
4004 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
4005 TDB_DATA key
, TDB_DATA data
, void *private_data
)
4007 struct backup_state
*state
= (struct backup_state
*)private_data
;
4011 if (state
->recbuf
== NULL
) {
4012 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4014 if (state
->recbuf
== NULL
) {
4019 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4025 len
= ctdb_rec_buffer_len(state
->recbuf
);
4026 if (len
< MAX_REC_BUFFER_SIZE
) {
4030 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4032 fprintf(stderr
, "Failed to write records to backup file\n");
4037 state
->nrec
+= state
->recbuf
->count
;
4038 TALLOC_FREE(state
->recbuf
);
4043 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4044 int argc
, const char **argv
)
4046 const char *db_name
;
4047 struct ctdb_db_context
*db
;
4050 struct backup_state state
;
4051 struct db_header db_hdr
;
4058 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4062 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4065 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4069 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4072 fprintf(stderr
, "Failed to open file %s for writing\n",
4077 /* Write empty header first */
4078 ZERO_STRUCT(db_hdr
);
4079 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4083 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4087 state
.mem_ctx
= mem_ctx
;
4088 state
.recbuf
= NULL
;
4093 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4095 fprintf(stderr
, "Failed to collect records from DB %s\n",
4101 if (state
.recbuf
!= NULL
) {
4102 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4105 "Failed to write records to backup file\n");
4111 state
.nrec
+= state
.recbuf
->count
;
4112 TALLOC_FREE(state
.recbuf
);
4115 db_hdr
.version
= DB_VERSION
;
4116 db_hdr
.timestamp
= time(NULL
);
4117 db_hdr
.flags
= db_flags
;
4118 db_hdr
.nbuf
= state
.nbuf
;
4119 db_hdr
.nrec
= state
.nrec
;
4120 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4122 lseek(fd
, 0, SEEK_SET
);
4123 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4127 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4132 printf("Database backed up to %s\n", argv
[1]);
4136 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4137 int argc
, const char **argv
)
4139 const char *db_name
= NULL
;
4140 struct ctdb_db_context
*db
;
4141 struct db_header db_hdr
;
4142 struct ctdb_node_map
*nodemap
;
4143 struct ctdb_req_control request
;
4144 struct ctdb_reply_control
**reply
;
4145 struct ctdb_transdb wipedb
;
4146 struct ctdb_pulldb_ext pulldb
;
4147 struct ctdb_rec_buffer
*recbuf
;
4148 uint32_t generation
;
4153 unsigned long i
, count
;
4157 if (argc
< 1 || argc
> 2) {
4161 fd
= open(argv
[0], O_RDONLY
, 0600);
4164 fprintf(stderr
, "Failed to open file %s for reading\n",
4173 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4177 fprintf(stderr
, "Failed to read db header from file %s\n",
4181 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4183 if (db_hdr
.version
!= DB_VERSION
) {
4185 "Wrong version of backup file, expected %u, got %lu\n",
4186 DB_VERSION
, db_hdr
.version
);
4191 if (db_name
== NULL
) {
4192 db_name
= db_hdr
.name
;
4195 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4196 localtime(&db_hdr
.timestamp
));
4197 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4199 db_flags
= db_hdr
.flags
& 0xff;
4200 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4203 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4208 nodemap
= get_nodemap(ctdb
, false);
4209 if (nodemap
== NULL
) {
4210 fprintf(stderr
, "Failed to get nodemap\n");
4215 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4217 fprintf(stderr
, "Failed to get current generation\n");
4222 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4229 wipedb
.db_id
= ctdb_db_id(db
);
4230 wipedb
.tid
= generation
;
4232 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4233 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4234 ctdb
->client
, pnn_list
, count
,
4235 TIMEOUT(), &request
, NULL
, NULL
);
4241 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4242 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4243 pnn_list
, count
, TIMEOUT(),
4244 &request
, NULL
, NULL
);
4249 ctdb_req_control_wipe_database(&request
, &wipedb
);
4250 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4251 pnn_list
, count
, TIMEOUT(),
4252 &request
, NULL
, NULL
);
4257 pulldb
.db_id
= ctdb_db_id(db
);
4259 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4261 ctdb_req_control_db_push_start(&request
, &pulldb
);
4262 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4263 pnn_list
, count
, TIMEOUT(),
4264 &request
, NULL
, NULL
);
4269 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4270 struct ctdb_req_message message
;
4274 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4279 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4280 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4281 if (data
.dptr
== NULL
) {
4285 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4287 message
.srvid
= pulldb
.srvid
;
4288 message
.data
.data
= data
;
4290 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4298 talloc_free(recbuf
);
4299 talloc_free(data
.dptr
);
4302 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4303 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4304 pnn_list
, count
, TIMEOUT(),
4305 &request
, NULL
, &reply
);
4310 for (i
=0; i
<count
; i
++) {
4311 uint32_t num_records
;
4313 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4316 fprintf(stderr
, "Invalid response from node %u\n",
4321 if (num_records
!= db_hdr
.nrec
) {
4322 fprintf(stderr
, "Node %u received %u of %lu records\n",
4323 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4328 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4329 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4330 pnn_list
, count
, TIMEOUT(),
4331 &request
, NULL
, NULL
);
4336 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4337 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4338 pnn_list
, count
, TIMEOUT(),
4339 &request
, NULL
, NULL
);
4344 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4345 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4346 ctdb
->client
, pnn_list
, count
,
4347 TIMEOUT(), &request
, NULL
, NULL
);
4352 printf("Database %s restored\n", db_name
);
4359 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4360 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4364 struct dumpdbbackup_state
{
4365 ctdb_rec_parser_func_t parser
;
4366 struct dump_record_state sub_state
;
4369 static int dumpdbbackup_handler(uint32_t reqid
,
4370 struct ctdb_ltdb_header
*header
,
4371 TDB_DATA key
, TDB_DATA data
,
4374 struct dumpdbbackup_state
*state
=
4375 (struct dumpdbbackup_state
*)private_data
;
4376 struct ctdb_ltdb_header hdr
;
4379 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4384 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4387 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4388 int argc
, const char **argv
)
4390 struct db_header db_hdr
;
4392 struct dumpdbbackup_state state
;
4398 usage("dumpbackup");
4401 fd
= open(argv
[0], O_RDONLY
, 0600);
4404 fprintf(stderr
, "Failed to open file %s for reading\n",
4409 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4413 fprintf(stderr
, "Failed to read db header from file %s\n",
4417 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4419 if (db_hdr
.version
!= DB_VERSION
) {
4421 "Wrong version of backup file, expected %u, got %lu\n",
4422 DB_VERSION
, db_hdr
.version
);
4427 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4428 localtime(&db_hdr
.timestamp
));
4429 printf("Dumping database %s from backup @ %s\n",
4430 db_hdr
.name
, timebuf
);
4432 state
.parser
= dump_record
;
4433 state
.sub_state
.count
= 0;
4435 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4436 struct ctdb_rec_buffer
*recbuf
;
4438 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4440 fprintf(stderr
, "Failed to read records\n");
4445 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4448 fprintf(stderr
, "Failed to dump records\n");
4455 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4459 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4460 int argc
, const char **argv
)
4462 const char *db_name
;
4463 struct ctdb_db_context
*db
;
4466 struct ctdb_node_map
*nodemap
;
4467 struct ctdb_req_control request
;
4468 struct ctdb_transdb wipedb
;
4469 uint32_t generation
;
4477 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4481 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4484 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4488 nodemap
= get_nodemap(ctdb
, false);
4489 if (nodemap
== NULL
) {
4490 fprintf(stderr
, "Failed to get nodemap\n");
4494 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4496 fprintf(stderr
, "Failed to get current generation\n");
4500 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4506 ctdb_req_control_db_freeze(&request
, db_id
);
4507 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4508 ctdb
->client
, pnn_list
, count
,
4509 TIMEOUT(), &request
, NULL
, NULL
);
4514 wipedb
.db_id
= db_id
;
4515 wipedb
.tid
= generation
;
4517 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4518 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4519 pnn_list
, count
, TIMEOUT(),
4520 &request
, NULL
, NULL
);
4525 ctdb_req_control_wipe_database(&request
, &wipedb
);
4526 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4527 pnn_list
, count
, TIMEOUT(),
4528 &request
, NULL
, NULL
);
4533 ctdb_req_control_db_set_healthy(&request
, db_id
);
4534 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4535 pnn_list
, count
, TIMEOUT(),
4536 &request
, NULL
, NULL
);
4541 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4542 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4543 pnn_list
, count
, TIMEOUT(),
4544 &request
, NULL
, NULL
);
4549 ctdb_req_control_db_thaw(&request
, db_id
);
4550 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4551 ctdb
->client
, pnn_list
, count
,
4552 TIMEOUT(), &request
, NULL
, NULL
);
4557 printf("Database %s wiped\n", db_name
);
4562 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4563 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4567 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4568 int argc
, const char **argv
)
4573 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4574 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4579 printf("%u\n", recmaster
);
4583 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4584 int argc
, const char **argv
)
4586 char *t
, *event_helper
= NULL
;
4588 t
= getenv("CTDB_EVENT_HELPER");
4590 event_helper
= talloc_strdup(mem_ctx
, t
);
4592 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb-event",
4593 CTDB_HELPER_BINDIR
);
4596 if (event_helper
== NULL
) {
4597 fprintf(stderr
, "Unable to set event daemon helper\n");
4601 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4605 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4606 int argc
, const char **argv
)
4608 const char *new_argv
[4];
4611 usage("scriptstatus");
4614 new_argv
[0] = "status";
4615 new_argv
[1] = "legacy";
4616 new_argv
[2] = (argc
== 0) ? "monitor" : argv
[0];
4619 (void) control_event(mem_ctx
, ctdb
, 3, new_argv
);
4623 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4624 int argc
, const char **argv
)
4626 char *t
, *natgw_helper
= NULL
;
4632 t
= getenv("CTDB_NATGW_HELPER");
4634 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4636 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4637 CTDB_HELPER_BINDIR
);
4640 if (natgw_helper
== NULL
) {
4641 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4645 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4650 * Find the PNN of the current node
4651 * discover the pnn by loading the nodes file and try to bind
4652 * to all addresses one at a time until the ip address is found.
4654 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4656 struct ctdb_node_map
*nodemap
;
4659 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4660 if (nodemap
== NULL
) {
4664 for (i
=0; i
<nodemap
->num
; i
++) {
4665 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4668 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4670 *pnn
= nodemap
->node
[i
].pnn
;
4672 talloc_free(nodemap
);
4677 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4678 talloc_free(nodemap
);
4682 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4683 int argc
, const char **argv
)
4685 const char *reclock
;
4689 usage("getreclock");
4692 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4693 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4698 if (reclock
!= NULL
) {
4699 printf("%s\n", reclock
);
4705 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4706 struct ctdb_context
*ctdb
,
4707 int argc
, const char **argv
)
4709 uint32_t lmasterrole
= 0;
4713 usage("setlmasterrole");
4716 if (strcmp(argv
[0], "on") == 0) {
4718 } else if (strcmp(argv
[0], "off") == 0) {
4721 usage("setlmasterrole");
4724 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4725 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4733 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4734 struct ctdb_context
*ctdb
,
4735 int argc
, const char **argv
)
4737 uint32_t recmasterrole
= 0;
4741 usage("setrecmasterrole");
4744 if (strcmp(argv
[0], "on") == 0) {
4746 } else if (strcmp(argv
[0], "off") == 0) {
4749 usage("setrecmasterrole");
4752 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4753 ctdb
->cmd_pnn
, TIMEOUT(),
4762 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4763 struct ctdb_context
*ctdb
,
4764 int argc
, const char **argv
)
4771 usage("setdbreadonly");
4774 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4778 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4779 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4783 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4784 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4792 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4793 int argc
, const char **argv
)
4800 usage("setdbsticky");
4803 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4807 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4808 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4812 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4813 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4821 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4822 int argc
, const char **argv
)
4824 const char *db_name
;
4825 struct ctdb_db_context
*db
;
4826 struct ctdb_transaction_handle
*h
;
4835 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4840 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4841 fprintf(stderr
, "Transactions not supported on DB %s\n",
4846 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4849 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4853 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4855 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4859 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4860 TIMEOUT(), db
, true, &h
);
4862 fprintf(stderr
, "Failed to start transaction on db %s\n",
4867 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4869 fprintf(stderr
, "Failed to read record for key %s\n",
4871 ctdb_transaction_cancel(h
);
4875 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4877 ctdb_transaction_cancel(h
);
4881 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4882 int argc
, const char **argv
)
4884 const char *db_name
;
4885 struct ctdb_db_context
*db
;
4886 struct ctdb_transaction_handle
*h
;
4895 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4900 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4901 fprintf(stderr
, "Transactions not supported on DB %s\n",
4906 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4909 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4913 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4915 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4919 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4921 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
4925 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4926 TIMEOUT(), db
, false, &h
);
4928 fprintf(stderr
, "Failed to start transaction on db %s\n",
4933 ret
= ctdb_transaction_store_record(h
, key
, data
);
4935 fprintf(stderr
, "Failed to store record for key %s\n",
4937 ctdb_transaction_cancel(h
);
4941 ret
= ctdb_transaction_commit(h
);
4943 fprintf(stderr
, "Failed to commit transaction on db %s\n",
4945 ctdb_transaction_cancel(h
);
4952 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4953 int argc
, const char **argv
)
4955 const char *db_name
;
4956 struct ctdb_db_context
*db
;
4957 struct ctdb_transaction_handle
*h
;
4966 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4971 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4972 fprintf(stderr
, "Transactions not supported on DB %s\n",
4977 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4980 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4984 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4986 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4990 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4991 TIMEOUT(), db
, false, &h
);
4993 fprintf(stderr
, "Failed to start transaction on db %s\n",
4998 ret
= ctdb_transaction_delete_record(h
, key
);
5000 fprintf(stderr
, "Failed to delete record for key %s\n",
5002 ctdb_transaction_cancel(h
);
5006 ret
= ctdb_transaction_commit(h
);
5008 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5010 ctdb_transaction_cancel(h
);
5017 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5025 /* Skip whitespace */
5026 n
= strspn(*ptr
, " \t");
5030 /* Quoted ASCII string - no wide characters! */
5032 n
= strcspn(t
, "\"");
5035 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5042 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5046 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5053 #define MAX_LINE_SIZE 1024
5055 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5056 TDB_DATA
*key
, TDB_DATA
*value
)
5058 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5062 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5068 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5069 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5070 /* Line Ignored but not EOF */
5076 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5078 /* Line Ignored but not EOF */
5079 talloc_free(key
->dptr
);
5087 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5088 int argc
, const char **argv
)
5090 const char *db_name
;
5091 struct ctdb_db_context
*db
;
5092 struct ctdb_transaction_handle
*h
;
5095 TDB_DATA key
= tdb_null
, value
= tdb_null
;
5098 if (argc
< 1 || argc
> 2) {
5102 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5107 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5108 fprintf(stderr
, "Transactions not supported on DB %s\n",
5114 file
= fopen(argv
[1], "r");
5116 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5123 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5126 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5130 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5131 TIMEOUT(), db
, false, &h
);
5133 fprintf(stderr
, "Failed to start transaction on db %s\n",
5138 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5139 if (key
.dsize
!= 0) {
5140 ret
= ctdb_transaction_store_record(h
, key
, value
);
5142 fprintf(stderr
, "Failed to store record\n");
5143 ctdb_transaction_cancel(h
);
5146 talloc_free(key
.dptr
);
5147 talloc_free(value
.dptr
);
5151 ret
= ctdb_transaction_commit(h
);
5153 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5155 ctdb_transaction_cancel(h
);
5159 if (file
!= stdin
) {
5165 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5166 int argc
, const char **argv
)
5168 struct tdb_context
*tdb
;
5170 struct ctdb_ltdb_header header
;
5173 if (argc
< 2 || argc
> 3) {
5177 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5179 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5183 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5185 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5190 data
= tdb_fetch(tdb
, key
);
5191 if (data
.dptr
== NULL
) {
5192 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5197 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5198 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5209 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5211 fprintf(stderr
, "Failed to open output file %s\n",
5216 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5217 if (nwritten
== -1 ||
5218 (size_t)nwritten
!= data
.dsize
) {
5219 fprintf(stderr
, "Failed to write record to file\n");
5228 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5230 fprintf(stderr
, "Failed to parse header from data\n");
5234 dump_ltdb_header(&header
);
5235 dump_tdb_data("data", data
);
5240 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5241 int argc
, const char **argv
)
5243 struct tdb_context
*tdb
;
5244 TDB_DATA key
, data
[2], value
;
5245 struct ctdb_ltdb_header header
;
5246 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5250 if (argc
< 3 || argc
> 5) {
5254 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5256 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5260 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5262 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5267 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5269 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5274 ZERO_STRUCT(header
);
5277 header
.rsn
= (uint64_t)smb_strtoull(argv
[3],
5287 header
.dmaster
= (uint32_t)atol(argv
[4]);
5290 header
.flags
= (uint32_t)atol(argv
[5]);
5293 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5296 data
[0].dptr
= header_buf
;
5298 data
[1].dsize
= value
.dsize
;
5299 data
[1].dptr
= value
.dptr
;
5301 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5303 fprintf(stderr
, "Failed to write record %s to file %s\n",
5312 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5313 int argc
, const char **argv
)
5315 const char *db_name
;
5316 struct ctdb_db_context
*db
;
5317 struct ctdb_record_handle
*h
;
5320 bool readonly
= false;
5323 if (argc
< 2 || argc
> 3) {
5328 if (strcmp(argv
[2], "readonly") == 0) {
5335 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5339 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5340 fprintf(stderr
, "DB %s is not a volatile database\n",
5345 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5348 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5352 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5354 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5358 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5359 db
, key
, readonly
, &h
, NULL
, &data
);
5361 fprintf(stderr
, "Failed to read record for key %s\n",
5364 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5365 (int)data
.dsize
, data
.dptr
);
5372 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5373 int argc
, const char **argv
)
5375 const char *db_name
;
5376 struct ctdb_db_context
*db
;
5377 struct ctdb_record_handle
*h
;
5386 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5390 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5391 fprintf(stderr
, "DB %s is not a volatile database\n",
5396 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5399 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5403 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5405 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5409 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5411 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5415 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5416 db
, key
, false, &h
, NULL
, NULL
);
5418 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5422 ret
= ctdb_store_record(h
, data
);
5424 fprintf(stderr
, "Failed to store record for key %s\n",
5432 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5433 int argc
, const char **argv
)
5435 const char *db_name
;
5436 struct ctdb_db_context
*db
;
5437 struct ctdb_record_handle
*h
;
5446 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5450 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5451 fprintf(stderr
, "DB %s is not a volatile database\n",
5456 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5459 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5463 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5465 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5469 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5470 db
, key
, false, &h
, NULL
, &data
);
5472 fprintf(stderr
, "Failed to fetch record for key %s\n",
5477 ret
= ctdb_delete_record(h
);
5479 fprintf(stderr
, "Failed to delete record for key %s\n",
5487 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5488 int argc
, const char **argv
)
5490 struct sockaddr_in sin
;
5496 usage("chktcpport");
5499 port
= atoi(argv
[0]);
5501 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5503 fprintf(stderr
, "Failed to open local socket\n");
5507 v
= fcntl(s
, F_GETFL
, 0);
5508 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5509 fprintf(stderr
, "Unable to set socket non-blocking\n");
5514 bzero(&sin
, sizeof(sin
));
5515 sin
.sin_family
= AF_INET
;
5516 sin
.sin_port
= htons(port
);
5517 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5520 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5527 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5528 int argc
, const char **argv
)
5531 const char *db_name
;
5536 usage("getdbseqnum");
5539 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5543 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5544 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5547 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5552 printf("0x%"PRIx64
"\n", seqnum
);
5556 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5557 int argc
, const char **argv
)
5559 const char *nodestring
= NULL
;
5560 struct ctdb_node_map
*nodemap
;
5563 bool print_hdr
= false;
5566 usage("nodestatus");
5570 nodestring
= argv
[0];
5571 if (strcmp(nodestring
, "all") == 0) {
5576 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5580 if (options
.machinereadable
) {
5581 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5583 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5587 for (i
=0; i
<nodemap
->num
; i
++) {
5588 uint32_t flags
= nodemap
->node
[i
].flags
;
5590 if ((flags
& NODE_FLAGS_DELETED
) != 0) {
5603 } db_stats_fields
[] = {
5604 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5605 DBSTATISTICS_FIELD(db_ro_delegations
),
5606 DBSTATISTICS_FIELD(db_ro_revokes
),
5607 DBSTATISTICS_FIELD(locks
.num_calls
),
5608 DBSTATISTICS_FIELD(locks
.num_current
),
5609 DBSTATISTICS_FIELD(locks
.num_pending
),
5610 DBSTATISTICS_FIELD(locks
.num_failed
),
5613 static void print_dbstatistics(const char *db_name
,
5614 struct ctdb_db_statistics
*s
)
5617 const char *prefix
= NULL
;
5620 printf("DB Statistics %s\n", db_name
);
5622 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5623 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5624 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5626 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5627 prefix
= db_stats_fields
[i
].name
;
5628 printf(" %*.*s\n", preflen
-1, preflen
-1,
5629 db_stats_fields
[i
].name
);
5634 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5635 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5636 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5639 printf(" hop_count_buckets:");
5640 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5641 printf(" %d", s
->hop_count_bucket
[i
]);
5645 printf(" lock_buckets:");
5646 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5647 printf(" %d", s
->locks
.buckets
[i
]);
5651 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5652 "locks_latency MIN/AVG/MAX",
5653 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5654 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5656 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5657 "vacuum_latency MIN/AVG/MAX",
5658 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5659 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5661 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5662 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5664 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5665 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5666 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5672 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5673 int argc
, const char **argv
)
5676 const char *db_name
;
5677 struct ctdb_db_statistics
*dbstats
;
5681 usage("dbstatistics");
5684 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5688 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5689 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5692 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5697 print_dbstatistics(db_name
, dbstats
);
5701 struct disable_takeover_runs_state
{
5703 unsigned int node_count
;
5709 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5712 struct disable_takeover_runs_state
*state
=
5713 (struct disable_takeover_runs_state
*)private_data
;
5717 if (data
.dsize
!= sizeof(int)) {
5722 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5723 ret
= *(int *)data
.dptr
;
5725 state
->status
= ret
;
5729 for (i
=0; i
<state
->node_count
; i
++) {
5730 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
5731 state
->reply
[i
] = true;
5737 for (i
=0; i
<state
->node_count
; i
++) {
5738 if (! state
->reply
[i
]) {
5739 state
->done
= false;
5745 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5746 struct ctdb_context
*ctdb
, uint32_t timeout
,
5747 uint32_t *pnn_list
, int count
)
5749 struct ctdb_disable_message disable
= { 0 };
5750 struct disable_takeover_runs_state state
;
5753 disable
.pnn
= ctdb
->pnn
;
5754 disable
.srvid
= next_srvid(ctdb
);
5755 disable
.timeout
= timeout
;
5757 state
.pnn_list
= pnn_list
;
5758 state
.node_count
= count
;
5761 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5762 if (state
.reply
== NULL
) {
5766 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5768 disable_takeover_run_handler
,
5774 for (i
=0; i
<count
; i
++) {
5775 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5784 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5786 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5788 ret
= (state
.status
>= 0 ? 0 : 1);
5792 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5793 disable
.srvid
, &state
);
5797 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5798 int argc
, const char **argv
)
5800 const char *nodestring
= NULL
;
5801 struct ctdb_node_map
*nodemap
, *nodemap2
;
5802 struct ctdb_req_control request
;
5803 uint32_t *pnn_list
, *pnn_list2
;
5804 int ret
, count
, count2
;
5811 nodestring
= argv
[0];
5814 nodemap
= get_nodemap(ctdb
, false);
5815 if (nodemap
== NULL
) {
5819 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5823 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5824 mem_ctx
, &pnn_list
);
5826 fprintf(stderr
, "Memory allocation error\n");
5830 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5831 mem_ctx
, &pnn_list2
);
5833 fprintf(stderr
, "Memory allocation error\n");
5837 /* Disable takeover runs on all connected nodes. A reply
5838 * indicating success is needed from each node so all nodes
5839 * will need to be active.
5841 * A check could be added to not allow reloading of IPs when
5842 * there are disconnected nodes. However, this should
5843 * probably be left up to the administrator.
5845 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5848 fprintf(stderr
, "Failed to disable takeover runs\n");
5852 /* Now tell all the desired nodes to reload their public IPs.
5853 * Keep trying this until it succeeds. This assumes all
5854 * failures are transient, which might not be true...
5856 ctdb_req_control_reload_public_ips(&request
);
5857 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5858 pnn_list2
, count2
, TIMEOUT(),
5859 &request
, NULL
, NULL
);
5861 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5864 /* It isn't strictly necessary to wait until takeover runs are
5865 * re-enabled but doing so can't hurt.
5867 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5869 fprintf(stderr
, "Failed to enable takeover runs\n");
5873 return ipreallocate(mem_ctx
, ctdb
);
5877 static const struct ctdb_cmd
{
5879 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5880 bool without_daemon
; /* can be run without daemon running ? */
5881 bool remote
; /* can be run on remote nodes */
5884 } ctdb_commands
[] = {
5885 { "version", control_version
, true, false,
5886 "show version of ctdb", NULL
},
5887 { "status", control_status
, false, true,
5888 "show node status", NULL
},
5889 { "uptime", control_uptime
, false, true,
5890 "show node uptime", NULL
},
5891 { "ping", control_ping
, false, true,
5892 "ping a node", NULL
},
5893 { "runstate", control_runstate
, false, true,
5894 "get/check runstate of a node",
5895 "[setup|first_recovery|startup|running]" },
5896 { "getvar", control_getvar
, false, true,
5897 "get a tunable variable", "<name>" },
5898 { "setvar", control_setvar
, false, true,
5899 "set a tunable variable", "<name> <value>" },
5900 { "listvars", control_listvars
, false, true,
5901 "list tunable variables", NULL
},
5902 { "statistics", control_statistics
, false, true,
5903 "show ctdb statistics", NULL
},
5904 { "statisticsreset", control_statistics_reset
, false, true,
5905 "reset ctdb statistics", NULL
},
5906 { "stats", control_stats
, false, true,
5907 "show rolling statistics", "[count]" },
5908 { "ip", control_ip
, false, true,
5909 "show public ips", "[all]" },
5910 { "ipinfo", control_ipinfo
, false, true,
5911 "show public ip details", "<ip>" },
5912 { "ifaces", control_ifaces
, false, true,
5913 "show interfaces", NULL
},
5914 { "setifacelink", control_setifacelink
, false, true,
5915 "set interface link status", "<iface> up|down" },
5916 { "process-exists", control_process_exists
, false, true,
5917 "check if a process exists on a node", "<pid> [<srvid>]" },
5918 { "getdbmap", control_getdbmap
, false, true,
5919 "show attached databases", NULL
},
5920 { "getdbstatus", control_getdbstatus
, false, true,
5921 "show database status", "<dbname|dbid>" },
5922 { "catdb", control_catdb
, false, false,
5923 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5924 { "cattdb", control_cattdb
, false, false,
5925 "dump local ctdb database", "<dbname|dbid>" },
5926 { "getcapabilities", control_getcapabilities
, false, true,
5927 "show node capabilities", NULL
},
5928 { "pnn", control_pnn
, false, false,
5929 "show the pnn of the currnet node", NULL
},
5930 { "lvs", control_lvs
, false, false,
5931 "show lvs configuration", "leader|list|status" },
5932 { "setdebug", control_setdebug
, false, true,
5933 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
5934 { "getdebug", control_getdebug
, false, true,
5935 "get debug level", NULL
},
5936 { "attach", control_attach
, false, false,
5937 "attach a database", "<dbname> [persistent|replicated]" },
5938 { "detach", control_detach
, false, false,
5939 "detach database(s)", "<dbname|dbid> ..." },
5940 { "dumpmemory", control_dumpmemory
, false, true,
5941 "dump ctdbd memory map", NULL
},
5942 { "rddumpmemory", control_rddumpmemory
, false, true,
5943 "dump recoverd memory map", NULL
},
5944 { "getpid", control_getpid
, false, true,
5945 "get ctdbd process ID", NULL
},
5946 { "disable", control_disable
, false, true,
5947 "disable a node", NULL
},
5948 { "enable", control_enable
, false, true,
5949 "enable a node", NULL
},
5950 { "stop", control_stop
, false, true,
5951 "stop a node", NULL
},
5952 { "continue", control_continue
, false, true,
5953 "continue a stopped node", NULL
},
5954 { "ban", control_ban
, false, true,
5955 "ban a node", "<bantime>"},
5956 { "unban", control_unban
, false, true,
5957 "unban a node", NULL
},
5958 { "shutdown", control_shutdown
, false, true,
5959 "shutdown ctdb daemon", NULL
},
5960 { "recover", control_recover
, false, true,
5961 "force recovery", NULL
},
5962 { "sync", control_ipreallocate
, false, true,
5963 "run ip reallocation (deprecated)", NULL
},
5964 { "ipreallocate", control_ipreallocate
, false, true,
5965 "run ip reallocation", NULL
},
5966 { "gratarp", control_gratarp
, false, true,
5967 "send a gratuitous arp", "<ip> <interface>" },
5968 { "tickle", control_tickle
, true, false,
5969 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5970 { "gettickles", control_gettickles
, false, true,
5971 "get the list of tickles", "<ip> [<port>]" },
5972 { "addtickle", control_addtickle
, false, true,
5973 "add a tickle", "<ip>:<port> <ip>:<port>" },
5974 { "deltickle", control_deltickle
, false, true,
5975 "delete a tickle", "<ip>:<port> <ip>:<port>" },
5976 { "listnodes", control_listnodes
, true, true,
5977 "list nodes in the cluster", NULL
},
5978 { "reloadnodes", control_reloadnodes
, false, false,
5979 "reload the nodes file all nodes", NULL
},
5980 { "moveip", control_moveip
, false, false,
5981 "move an ip address to another node", "<ip> <node>" },
5982 { "addip", control_addip
, false, true,
5983 "add an ip address to a node", "<ip/mask> <iface>" },
5984 { "delip", control_delip
, false, true,
5985 "delete an ip address from a node", "<ip>" },
5986 { "backupdb", control_backupdb
, false, false,
5987 "backup a database into a file", "<dbname|dbid> <file>" },
5988 { "restoredb", control_restoredb
, false, false,
5989 "restore a database from a file", "<file> [dbname]" },
5990 { "dumpdbbackup", control_dumpdbbackup
, true, false,
5991 "dump database from a backup file", "<file>" },
5992 { "wipedb", control_wipedb
, false, false,
5993 "wipe the contents of a database.", "<dbname|dbid>"},
5994 { "recmaster", control_recmaster
, false, true,
5995 "show the pnn for the recovery master", NULL
},
5996 { "event", control_event
, true, false,
5997 "event and event script commands", NULL
},
5998 { "scriptstatus", control_scriptstatus
, true, false,
5999 "show event script status",
6000 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6001 { "natgw", control_natgw
, false, false,
6002 "show natgw configuration", "leader|list|status" },
6003 { "getreclock", control_getreclock
, false, true,
6004 "get recovery lock file", NULL
},
6005 { "setlmasterrole", control_setlmasterrole
, false, true,
6006 "set LMASTER role", "on|off" },
6007 { "setrecmasterrole", control_setrecmasterrole
, false, true,
6008 "set RECMASTER role", "on|off"},
6009 { "setdbreadonly", control_setdbreadonly
, false, true,
6010 "enable readonly records", "<dbname|dbid>" },
6011 { "setdbsticky", control_setdbsticky
, false, true,
6012 "enable sticky records", "<dbname|dbid>"},
6013 { "pfetch", control_pfetch
, false, false,
6014 "fetch record from persistent database", "<dbname|dbid> <key>" },
6015 { "pstore", control_pstore
, false, false,
6016 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6017 { "pdelete", control_pdelete
, false, false,
6018 "delete record from persistent database", "<dbname|dbid> <key>" },
6019 { "ptrans", control_ptrans
, false, false,
6020 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6021 { "tfetch", control_tfetch
, false, true,
6022 "fetch a record", "<tdb-file> <key> [<file>]" },
6023 { "tstore", control_tstore
, false, true,
6024 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6025 { "readkey", control_readkey
, false, false,
6026 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6027 { "writekey", control_writekey
, false, false,
6028 "write value for a database key", "<dbname|dbid> <key> <value>" },
6029 { "deletekey", control_deletekey
, false, false,
6030 "delete a database key", "<dbname|dbid> <key>" },
6031 { "checktcpport", control_checktcpport
, true, false,
6032 "check if a service is bound to a specific tcp port or not", "<port>" },
6033 { "getdbseqnum", control_getdbseqnum
, false, false,
6034 "get database sequence number", "<dbname|dbid>" },
6035 { "nodestatus", control_nodestatus
, false, true,
6036 "show and return node status", "[all|<pnn-list>]" },
6037 { "dbstatistics", control_dbstatistics
, false, true,
6038 "show database statistics", "<dbname|dbid>" },
6039 { "reloadips", control_reloadips
, false, false,
6040 "reload the public addresses file", "[all|<pnn-list>]" },
6043 static const struct ctdb_cmd
*match_command(const char *command
)
6045 const struct ctdb_cmd
*cmd
;
6048 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6049 cmd
= &ctdb_commands
[i
];
6050 if (strlen(command
) == strlen(cmd
->name
) &&
6051 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6061 * Show usage message
6063 static void usage_full(void)
6067 poptPrintHelp(pc
, stdout
, 0);
6068 printf("\nCommands:\n");
6069 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6070 printf(" %-15s %-27s %s\n",
6071 ctdb_commands
[i
].name
,
6072 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6073 ctdb_commands
[i
].msg
);
6077 static void usage(const char *command
)
6079 const struct ctdb_cmd
*cmd
;
6081 if (command
== NULL
) {
6086 cmd
= match_command(command
);
6090 poptPrintUsage(pc
, stdout
, 0);
6091 printf("\nCommands:\n");
6092 printf(" %-15s %-27s %s\n",
6093 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6099 struct poptOption cmdline_options
[] = {
6102 .longName
= "debug",
6104 .argInfo
= POPT_ARG_STRING
,
6105 .arg
= &options
.debuglevelstr
,
6107 .descrip
= "debug level",
6110 .longName
= "timelimit",
6112 .argInfo
= POPT_ARG_INT
,
6113 .arg
= &options
.timelimit
,
6115 .descrip
= "timelimit (in seconds)",
6120 .argInfo
= POPT_ARG_INT
,
6121 .arg
= &options
.pnn
,
6123 .descrip
= "node specification - integer",
6128 .argInfo
= POPT_ARG_NONE
,
6129 .arg
= &options
.machinereadable
,
6131 .descrip
= "enable machine readable output",
6134 .longName
= "separator",
6136 .argInfo
= POPT_ARG_STRING
,
6137 .arg
= &options
.sep
,
6139 .descrip
= "specify separator for machine readable output",
6140 .argDescrip
= "CHAR",
6144 .argInfo
= POPT_ARG_NONE
,
6145 .arg
= &options
.machineparsable
,
6147 .descrip
= "enable machine parsable output with separator |",
6150 .longName
= "verbose",
6152 .argInfo
= POPT_ARG_NONE
,
6153 .arg
= &options
.verbose
,
6155 .descrip
= "enable verbose output",
6158 .longName
= "maxruntime",
6160 .argInfo
= POPT_ARG_INT
,
6161 .arg
= &options
.maxruntime
,
6163 .descrip
= "die if runtime exceeds this limit (in seconds)",
6168 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6171 TALLOC_CTX
*tmp_ctx
;
6172 struct ctdb_context
*ctdb
;
6173 const char *ctdb_socket
;
6176 uint64_t srvid_offset
;
6178 tmp_ctx
= talloc_new(NULL
);
6179 if (tmp_ctx
== NULL
) {
6180 fprintf(stderr
, "Memory allocation error\n");
6184 if (cmd
->without_daemon
) {
6185 if (options
.pnn
!= -1) {
6187 "Cannot specify node for command %s\n",
6192 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6193 talloc_free(tmp_ctx
);
6197 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6199 fprintf(stderr
, "Memory allocation error\n");
6203 ctdb
->ev
= tevent_context_init(ctdb
);
6204 if (ctdb
->ev
== NULL
) {
6205 fprintf(stderr
, "Failed to initialize tevent\n");
6209 ctdb_socket
= path_socket(ctdb
, "ctdbd");
6210 if (ctdb_socket
== NULL
) {
6211 fprintf(stderr
, "Memory allocation error\n");
6215 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6217 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6220 if (!find_node_xpnn(ctdb
, NULL
)) {
6221 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6226 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6227 srvid_offset
= getpid() & 0xFFFF;
6228 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6230 if (options
.pnn
!= -1) {
6231 status
= verify_pnn(ctdb
, options
.pnn
);
6236 ctdb
->cmd_pnn
= options
.pnn
;
6238 ctdb
->cmd_pnn
= ctdb
->pnn
;
6241 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6242 fprintf(stderr
, "Node cannot be specified for command %s\n",
6247 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6248 talloc_free(tmp_ctx
);
6252 talloc_free(tmp_ctx
);
6256 static void signal_handler(int sig
)
6258 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6261 static void alarm_handler(int sig
)
6263 /* Kill any child processes */
6264 signal(SIGTERM
, signal_handler
);
6270 int main(int argc
, const char *argv
[])
6273 const char **extra_argv
;
6275 const struct ctdb_cmd
*cmd
;
6276 const char *test_mode
;
6283 /* Set default options */
6284 options
.debuglevelstr
= NULL
;
6285 options
.timelimit
= 10;
6287 options
.maxruntime
= 0;
6290 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6291 POPT_CONTEXT_KEEP_FIRST
);
6292 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6293 fprintf(stderr
, "Invalid option %s: %s\n",
6294 poptBadOption(pc
, 0), poptStrerror(opt
));
6298 if (options
.maxruntime
== 0) {
6299 const char *ctdb_timeout
;
6301 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6302 if (ctdb_timeout
!= NULL
) {
6303 options
.maxruntime
= smb_strtoul(ctdb_timeout
,
6309 fprintf(stderr
, "Invalid value CTDB_TIMEOUT\n");
6313 options
.maxruntime
= 120;
6317 if (options
.machineparsable
) {
6318 options
.machinereadable
= 1;
6321 /* setup the remaining options for the commands */
6323 extra_argv
= poptGetArgs(pc
);
6326 while (extra_argv
[extra_argc
]) extra_argc
++;
6329 if (extra_argc
< 1) {
6333 cmd
= match_command(extra_argv
[0]);
6335 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6339 /* Enable logging */
6340 setup_logging("ctdb", DEBUG_STDERR
);
6341 ok
= debug_level_parse(options
.debuglevelstr
, &loglevel
);
6343 loglevel
= DEBUG_ERR
;
6345 debuglevel_set(loglevel
);
6347 /* Stop process group kill in alarm_handler() from killing tests */
6348 test_mode
= getenv("CTDB_TEST_MODE");
6349 if (test_mode
!= NULL
) {
6350 const char *have_setpgid
= getenv("CTDB_TOOL_SETPGID");
6351 if (have_setpgid
== NULL
) {
6353 setenv("CTDB_TOOL_SETPGID", "1", 1);
6357 signal(SIGALRM
, alarm_handler
);
6358 alarm(options
.maxruntime
);
6360 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6365 (void)poptFreeContext(pc
);