4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
33 #include "ctdb_version.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/sys_rw.h"
38 #include "common/db_hash.h"
39 #include "common/logging.h"
40 #include "protocol/protocol.h"
41 #include "protocol/protocol_api.h"
42 #include "common/system.h"
43 #include "client/client.h"
45 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
47 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
48 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
52 const char *debuglevelstr
;
60 int printemptyrecords
;
67 static poptContext pc
;
70 struct tevent_context
*ev
;
71 struct ctdb_client_context
*client
;
72 struct ctdb_node_map
*nodemap
;
73 uint32_t pnn
, cmd_pnn
;
77 static void usage(const char *command
);
83 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
85 return (tv2
->tv_sec
- tv
->tv_sec
) +
86 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
89 static struct ctdb_node_and_flags
*get_node_by_pnn(
90 struct ctdb_node_map
*nodemap
,
95 for (i
=0; i
<nodemap
->num
; i
++) {
96 if (nodemap
->node
[i
].pnn
== pnn
) {
97 return &nodemap
->node
[i
];
103 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
105 static const struct {
109 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
110 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
111 { NODE_FLAGS_BANNED
, "BANNED" },
112 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
113 { NODE_FLAGS_DELETED
, "DELETED" },
114 { NODE_FLAGS_STOPPED
, "STOPPED" },
115 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
117 char *flags_str
= NULL
;
120 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
121 if (flags
& flag_names
[i
].flag
) {
122 if (flags_str
== NULL
) {
123 flags_str
= talloc_asprintf(mem_ctx
,
124 "%s", flag_names
[i
].name
);
126 flags_str
= talloc_asprintf_append(flags_str
,
127 "|%s", flag_names
[i
].name
);
129 if (flags_str
== NULL
) {
130 return "OUT-OF-MEMORY";
134 if (flags_str
== NULL
) {
141 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
148 * Get consistent nodemap information.
150 * If nodemap is already cached, use that. If not get it.
151 * If the current node is BANNED, then get nodemap from "better" node.
153 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
156 struct ctdb_node_map
*nodemap
;
157 struct ctdb_node_and_flags
*node
;
158 uint32_t current_node
;
162 TALLOC_FREE(ctdb
->nodemap
);
165 if (ctdb
->nodemap
!= NULL
) {
166 return ctdb
->nodemap
;
169 tmp_ctx
= talloc_new(ctdb
);
170 if (tmp_ctx
== NULL
) {
174 current_node
= ctdb
->pnn
;
176 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
177 current_node
, TIMEOUT(), &nodemap
);
179 fprintf(stderr
, "Failed to get nodemap from node %u\n",
184 node
= get_node_by_pnn(nodemap
, current_node
);
185 if (node
->flags
& NODE_FLAGS_BANNED
) {
188 current_node
= (current_node
+ 1) % nodemap
->num
;
189 node
= get_node_by_pnn(nodemap
, current_node
);
191 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
194 } while (current_node
!= ctdb
->pnn
);
196 if (current_node
== ctdb
->pnn
) {
197 /* Tried all nodes in the cluster */
198 fprintf(stderr
, "Warning: All nodes are banned.\n");
205 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
209 talloc_free(tmp_ctx
);
213 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
215 struct ctdb_node_map
*nodemap
;
223 nodemap
= get_nodemap(ctdb
, false);
224 if (nodemap
== NULL
) {
229 for (i
=0; i
<nodemap
->num
; i
++) {
230 if (nodemap
->node
[i
].pnn
== pnn
) {
236 fprintf(stderr
, "Node %u does not exist\n", pnn
);
240 if (nodemap
->node
[i
].flags
&
241 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
242 fprintf(stderr
, "Node %u has status %s\n", pnn
,
243 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
250 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
251 struct ctdb_node_map
*nodemap
)
253 struct ctdb_node_map
*nodemap2
;
255 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
256 if (nodemap2
== NULL
) {
260 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
262 if (nodemap2
->node
== NULL
) {
263 talloc_free(nodemap2
);
271 * Get the number and the list of matching nodes
273 * nodestring := NULL | all | pnn,[pnn,...]
275 * If nodestring is NULL, use the current node.
277 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
278 const char *nodestring
,
279 struct ctdb_node_map
**out
)
281 struct ctdb_node_map
*nodemap
, *nodemap2
;
282 struct ctdb_node_and_flags
*node
;
285 nodemap
= get_nodemap(ctdb
, false);
286 if (nodemap
== NULL
) {
290 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
291 if (nodemap2
== NULL
) {
295 if (nodestring
== NULL
) {
296 for (i
=0; i
<nodemap
->num
; i
++) {
297 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
298 nodemap2
->node
[0] = nodemap
->node
[i
];
307 if (strcmp(nodestring
, "all") == 0) {
308 for (i
=0; i
<nodemap
->num
; i
++) {
309 nodemap2
->node
[i
] = nodemap
->node
[i
];
311 nodemap2
->num
= nodemap
->num
;
317 ns
= talloc_strdup(mem_ctx
, nodestring
);
322 tok
= strtok(ns
, ",");
323 while (tok
!= NULL
) {
327 pnn
= (uint32_t)strtoul(tok
, &endptr
, 0);
328 if (pnn
== 0 && tok
== endptr
) {
329 fprintf(stderr
, "Invalid node %s\n", tok
);
333 node
= get_node_by_pnn(nodemap
, pnn
);
335 fprintf(stderr
, "Node %u does not exist\n",
340 nodemap2
->node
[nodemap2
->num
] = *node
;
343 tok
= strtok(NULL
, ",");
352 /* Compare IP address */
353 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
357 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
361 switch (ip1
->sa
.sa_family
) {
363 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
364 sizeof(struct in_addr
)) == 0);
368 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
369 sizeof(struct in6_addr
)) == 0);
376 /* Append a node to a node map with given address and flags */
377 static bool node_map_add(struct ctdb_node_map
*nodemap
,
378 const char *nstr
, uint32_t flags
)
382 struct ctdb_node_and_flags
*n
;
384 if (! parse_ip(nstr
, NULL
, 0, &addr
)) {
385 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
390 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
391 struct ctdb_node_and_flags
, num
+1);
392 if (nodemap
->node
== NULL
) {
396 n
= &nodemap
->node
[num
];
401 nodemap
->num
= num
+1;
405 /* Read a nodes file into a node map */
406 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
412 struct ctdb_node_map
*nodemap
;
414 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
415 if (nodemap
== NULL
) {
419 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
424 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
428 for (i
=0; i
<nlines
; i
++) {
434 /* strip leading spaces */
435 while((*node
== ' ') || (*node
== '\t')) {
441 /* strip trailing spaces */
443 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
453 /* A "deleted" node is a node that is
454 commented out in the nodes file. This is
455 used instead of removing a line, which
456 would cause subsequent nodes to change
458 flags
= NODE_FLAGS_DELETED
;
459 node
= discard_const("0.0.0.0");
463 if (! node_map_add(nodemap
, node
, flags
)) {
465 TALLOC_FREE(nodemap
);
474 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
476 struct ctdb_node_map
*nodemap
;
478 const char *nodes_list
= NULL
;
480 if (pnn
!= CTDB_UNKNOWN_PNN
) {
481 nodepath
= talloc_asprintf(mem_ctx
, "CTDB_NODES_%u", pnn
);
482 if (nodepath
!= NULL
) {
483 nodes_list
= getenv(nodepath
);
486 if (nodes_list
== NULL
) {
487 nodes_list
= getenv("CTDB_NODES");
489 if (nodes_list
== NULL
) {
490 const char *basedir
= getenv("CTDB_BASE");
491 if (basedir
== NULL
) {
492 basedir
= CTDB_ETCDIR
;
494 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
495 if (nodes_list
== NULL
) {
496 fprintf(stderr
, "Memory allocation error\n");
501 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
502 if (nodemap
== NULL
) {
503 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
511 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
512 struct ctdb_context
*ctdb
,
513 struct ctdb_dbid_map
*dbmap
,
516 struct ctdb_dbid
*db
= NULL
;
520 for (i
=0; i
<dbmap
->num
; i
++) {
521 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
522 ctdb
->pnn
, TIMEOUT(),
523 dbmap
->dbs
[i
].db_id
, &name
);
528 if (strcmp(db_name
, name
) == 0) {
529 talloc_free(discard_const(name
));
538 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
539 const char *db_arg
, uint32_t *db_id
,
540 const char **db_name
, uint8_t *db_flags
)
542 struct ctdb_dbid_map
*dbmap
;
543 struct ctdb_dbid
*db
= NULL
;
545 const char *name
= NULL
;
548 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
549 ctdb
->pnn
, TIMEOUT(), &dbmap
);
554 if (strncmp(db_arg
, "0x", 2) == 0) {
555 id
= strtoul(db_arg
, NULL
, 0);
556 for (i
=0; i
<dbmap
->num
; i
++) {
557 if (id
== dbmap
->dbs
[i
].db_id
) {
564 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
568 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
573 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
574 ctdb
->pnn
, TIMEOUT(), id
, &name
);
583 if (db_name
!= NULL
) {
584 *db_name
= talloc_strdup(mem_ctx
, name
);
586 if (db_flags
!= NULL
) {
587 *db_flags
= db
->flags
;
592 static int h2i(char h
)
594 if (h
>= 'a' && h
<= 'f') {
597 if (h
>= 'A' && h
<= 'F') {
603 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
610 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
615 data
.dsize
= len
/ 2;
616 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
617 if (data
.dptr
== NULL
) {
621 for (i
=0; i
<data
.dsize
; i
++) {
622 data
.dptr
[i
] = h2i(str
[i
*2]) << 4 | h2i(str
[i
*2+1]);
629 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
635 if (strncmp(str
, "0x", 2) == 0) {
636 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
638 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
639 if (data
.dptr
== NULL
) {
649 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
650 const char *path
, int argc
, const char **argv
)
653 int save_errno
, status
, ret
;
654 const char **new_argv
;
657 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
658 if (new_argv
== NULL
) {
663 for (i
=0; i
<argc
; i
++) {
664 new_argv
[i
+1] = argv
[i
];
666 new_argv
[argc
+1] = NULL
;
671 talloc_free(new_argv
);
672 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
673 command
, path
, strerror(save_errno
));
678 ret
= execv(path
, discard_const(new_argv
));
682 /* Should not happen */
686 talloc_free(new_argv
);
688 ret
= waitpid(pid
, &status
, 0);
691 fprintf(stderr
, "waitpid() failed for %s - %s\n",
692 command
, strerror(save_errno
));
696 if (WIFEXITED(status
)) {
697 int pstatus
= WEXITSTATUS(status
);
698 if (WIFSIGNALED(status
)) {
699 fprintf(stderr
, "%s terminated with signal %d\n",
700 command
, WTERMSIG(status
));
702 } else if (pstatus
>= 64 && pstatus
< 255) {
703 fprintf(stderr
, "%s failed with error %d\n",
704 command
, pstatus
-64);
710 } else if (WIFSIGNALED(status
)) {
711 fprintf(stderr
, "%s terminated with signal %d\n",
712 command
, WTERMSIG(status
));
723 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
724 int argc
, const char **argv
)
726 printf("%s\n", CTDB_VERSION_STRING
);
730 static bool partially_online(TALLOC_CTX
*mem_ctx
,
731 struct ctdb_context
*ctdb
,
732 struct ctdb_node_and_flags
*node
)
734 struct ctdb_iface_list
*iface_list
;
738 if (node
->flags
!= 0) {
742 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
743 node
->pnn
, TIMEOUT(), &iface_list
);
749 for (i
=0; i
< iface_list
->num
; i
++) {
750 if (iface_list
->iface
[i
].link_state
== 0) {
759 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
760 struct ctdb_context
*ctdb
,
761 struct ctdb_node_map
*nodemap
,
764 struct ctdb_node_and_flags
*node
;
767 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
771 "Disconnected", options
.sep
,
772 "Banned", options
.sep
,
773 "Disabled", options
.sep
,
774 "Unhealthy", options
.sep
,
775 "Stopped", options
.sep
,
776 "Inactive", options
.sep
,
777 "PartiallyOnline", options
.sep
,
778 "ThisNode", options
.sep
);
780 for (i
=0; i
<nodemap
->num
; i
++) {
781 node
= &nodemap
->node
[i
];
782 if (node
->flags
& NODE_FLAGS_DELETED
) {
786 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
788 node
->pnn
, options
.sep
,
789 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
),
791 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
792 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
793 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
795 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
796 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
797 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
798 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
799 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
804 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
805 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
808 struct ctdb_node_and_flags
*node
;
809 int num_deleted_nodes
= 0;
812 for (i
=0; i
<nodemap
->num
; i
++) {
813 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
819 if (num_deleted_nodes
== 0) {
820 printf("Number of nodes:%d\n", nodemap
->num
);
822 printf("Number of nodes:%d "
823 "(including %d deleted nodes)\n",
824 nodemap
->num
, num_deleted_nodes
);
828 for (i
=0; i
<nodemap
->num
; i
++) {
829 node
= &nodemap
->node
[i
];
830 if (node
->flags
& NODE_FLAGS_DELETED
) {
834 printf("pnn:%u %-16s %s%s\n",
836 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
),
837 partially_online(mem_ctx
, ctdb
, node
) ?
839 pretty_print_flags(mem_ctx
, node
->flags
),
840 node
->pnn
== mypnn
? " (THIS NODE)" : "");
844 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
845 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
846 struct ctdb_vnn_map
*vnnmap
, int recmode
,
851 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
853 if (vnnmap
->generation
== INVALID_GENERATION
) {
854 printf("Generation:INVALID\n");
856 printf("Generation:%u\n", vnnmap
->generation
);
858 printf("Size:%d\n", vnnmap
->size
);
859 for (i
=0; i
<vnnmap
->size
; i
++) {
860 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
863 printf("Recovery mode:%s (%d)\n",
864 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
866 printf("Recovery master:%d\n", recmaster
);
869 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
870 int argc
, const char **argv
)
872 struct ctdb_node_map
*nodemap
;
873 struct ctdb_vnn_map
*vnnmap
;
882 nodemap
= get_nodemap(ctdb
, false);
883 if (nodemap
== NULL
) {
887 if (options
.machinereadable
== 1) {
888 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
892 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
893 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
898 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
899 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
904 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
905 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
910 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
915 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
916 int argc
, const char **argv
)
918 struct ctdb_uptime
*uptime
;
919 int ret
, tmp
, days
, hours
, minutes
, seconds
;
921 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
922 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
927 printf("Current time of node %-4u : %s",
928 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
930 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
931 seconds
= tmp
% 60; tmp
/= 60;
932 minutes
= tmp
% 60; tmp
/= 60;
933 hours
= tmp
% 24; tmp
/= 24;
936 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
937 days
, hours
, minutes
, seconds
,
938 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
940 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
941 seconds
= tmp
% 60; tmp
/= 60;
942 minutes
= tmp
% 60; tmp
/= 60;
943 hours
= tmp
% 24; tmp
/= 24;
946 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
947 days
, hours
, minutes
, seconds
,
948 ctime(&uptime
->last_recovery_finished
.tv_sec
));
950 printf("Duration of last recovery/failover: %lf seconds\n",
951 timeval_delta(&uptime
->last_recovery_finished
,
952 &uptime
->last_recovery_started
));
957 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
958 int argc
, const char **argv
)
961 int ret
, num_clients
;
963 tv
= timeval_current();
964 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
965 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
970 printf("response from %u time=%.6f sec (%d clients)\n",
971 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
975 const char *runstate_to_string(enum ctdb_runstate runstate
);
976 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
978 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
979 int argc
, const char **argv
)
981 enum ctdb_runstate runstate
;
985 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
986 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
992 for (i
=0; i
<argc
; i
++) {
993 enum ctdb_runstate t
;
996 t
= ctdb_runstate_from_string(argv
[i
]);
997 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
998 printf("Invalid run state (%s)\n", argv
[i
]);
1002 if (t
== runstate
) {
1009 printf("CTDB not in required run state (got %s)\n",
1010 ctdb_runstate_to_string(runstate
));
1014 printf("%s\n", ctdb_runstate_to_string(runstate
));
1018 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1019 int argc
, const char **argv
)
1021 struct ctdb_var_list
*tun_var_list
;
1030 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1031 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1034 "Failed to get list of variables from node %u\n",
1040 for (i
=0; i
<tun_var_list
->count
; i
++) {
1041 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1048 printf("No such tunable %s\n", argv
[0]);
1052 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1053 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1058 printf("%-26s = %u\n", argv
[0], value
);
1062 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1063 int argc
, const char **argv
)
1065 struct ctdb_var_list
*tun_var_list
;
1066 struct ctdb_tunable tunable
;
1074 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1075 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1078 "Failed to get list of variables from node %u\n",
1084 for (i
=0; i
<tun_var_list
->count
; i
++) {
1085 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1092 printf("No such tunable %s\n", argv
[0]);
1096 tunable
.name
= argv
[0];
1097 tunable
.value
= strtoul(argv
[1], NULL
, 0);
1099 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1100 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1104 "Setting obsolete tunable variable '%s'\n",
1113 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1114 int argc
, const char **argv
)
1116 struct ctdb_var_list
*tun_var_list
;
1123 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1124 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1129 for (i
=0; i
<tun_var_list
->count
; i
++) {
1130 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1139 } stats_fields
[] = {
1140 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1141 STATISTICS_FIELD(num_clients
),
1142 STATISTICS_FIELD(frozen
),
1143 STATISTICS_FIELD(recovering
),
1144 STATISTICS_FIELD(num_recoveries
),
1145 STATISTICS_FIELD(client_packets_sent
),
1146 STATISTICS_FIELD(client_packets_recv
),
1147 STATISTICS_FIELD(node_packets_sent
),
1148 STATISTICS_FIELD(node_packets_recv
),
1149 STATISTICS_FIELD(keepalive_packets_sent
),
1150 STATISTICS_FIELD(keepalive_packets_recv
),
1151 STATISTICS_FIELD(node
.req_call
),
1152 STATISTICS_FIELD(node
.reply_call
),
1153 STATISTICS_FIELD(node
.req_dmaster
),
1154 STATISTICS_FIELD(node
.reply_dmaster
),
1155 STATISTICS_FIELD(node
.reply_error
),
1156 STATISTICS_FIELD(node
.req_message
),
1157 STATISTICS_FIELD(node
.req_control
),
1158 STATISTICS_FIELD(node
.reply_control
),
1159 STATISTICS_FIELD(client
.req_call
),
1160 STATISTICS_FIELD(client
.req_message
),
1161 STATISTICS_FIELD(client
.req_control
),
1162 STATISTICS_FIELD(timeouts
.call
),
1163 STATISTICS_FIELD(timeouts
.control
),
1164 STATISTICS_FIELD(timeouts
.traverse
),
1165 STATISTICS_FIELD(locks
.num_calls
),
1166 STATISTICS_FIELD(locks
.num_current
),
1167 STATISTICS_FIELD(locks
.num_pending
),
1168 STATISTICS_FIELD(locks
.num_failed
),
1169 STATISTICS_FIELD(total_calls
),
1170 STATISTICS_FIELD(pending_calls
),
1171 STATISTICS_FIELD(childwrite_calls
),
1172 STATISTICS_FIELD(pending_childwrite_calls
),
1173 STATISTICS_FIELD(memory_used
),
1174 STATISTICS_FIELD(max_hop_count
),
1175 STATISTICS_FIELD(total_ro_delegations
),
1176 STATISTICS_FIELD(total_ro_revokes
),
1179 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1181 static void print_statistics_machine(struct ctdb_statistics
*s
,
1187 printf("CTDB version%s", options
.sep
);
1188 printf("Current time of statistics%s", options
.sep
);
1189 printf("Statistics collected since%s", options
.sep
);
1190 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1191 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1193 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1194 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1195 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1196 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1198 printf("num_reclock_recd_latency%s", options
.sep
);
1199 printf("min_reclock_recd_latency%s", options
.sep
);
1200 printf("avg_reclock_recd_latency%s", options
.sep
);
1201 printf("max_reclock_recd_latency%s", options
.sep
);
1203 printf("num_call_latency%s", options
.sep
);
1204 printf("min_call_latency%s", options
.sep
);
1205 printf("avg_call_latency%s", options
.sep
);
1206 printf("max_call_latency%s", options
.sep
);
1208 printf("num_lockwait_latency%s", options
.sep
);
1209 printf("min_lockwait_latency%s", options
.sep
);
1210 printf("avg_lockwait_latency%s", options
.sep
);
1211 printf("max_lockwait_latency%s", options
.sep
);
1213 printf("num_childwrite_latency%s", options
.sep
);
1214 printf("min_childwrite_latency%s", options
.sep
);
1215 printf("avg_childwrite_latency%s", options
.sep
);
1216 printf("max_childwrite_latency%s", options
.sep
);
1220 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1221 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1222 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1223 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1225 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1228 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1229 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1230 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1231 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1233 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1234 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1235 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1236 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1238 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1239 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1240 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1241 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1243 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1244 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1245 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1246 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1250 static void print_statistics(struct ctdb_statistics
*s
)
1252 int tmp
, days
, hours
, minutes
, seconds
;
1254 const char *prefix
= NULL
;
1257 tmp
= s
->statistics_current_time
.tv_sec
-
1258 s
->statistics_start_time
.tv_sec
;
1259 seconds
= tmp
% 60; tmp
/= 60;
1260 minutes
= tmp
% 60; tmp
/= 60;
1261 hours
= tmp
% 24; tmp
/= 24;
1264 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1265 printf("Current time of statistics : %s",
1266 ctime(&s
->statistics_current_time
.tv_sec
));
1267 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1268 days
, hours
, minutes
, seconds
,
1269 ctime(&s
->statistics_start_time
.tv_sec
));
1271 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1272 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1273 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1275 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1276 prefix
= stats_fields
[i
].name
;
1277 printf(" %*.*s\n", preflen
-1, preflen
-1,
1278 stats_fields
[i
].name
);
1283 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1284 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1285 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1288 printf(" hop_count_buckets:");
1289 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1290 printf(" %d", s
->hop_count_bucket
[i
]);
1293 printf(" lock_buckets:");
1294 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1295 printf(" %d", s
->locks
.buckets
[i
]);
1298 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1299 "locks_latency MIN/AVG/MAX",
1300 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1301 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1303 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1304 "reclock_ctdbd MIN/AVG/MAX",
1305 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1306 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1308 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1309 "reclock_recd MIN/AVG/MAX",
1310 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1311 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1313 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1314 "call_latency MIN/AVG/MAX",
1315 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1316 s
->call_latency
.max
, s
->call_latency
.num
);
1318 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1319 "childwrite_latency MIN/AVG/MAX",
1320 s
->childwrite_latency
.min
,
1321 LATENCY_AVG(s
->childwrite_latency
),
1322 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1325 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1326 int argc
, const char **argv
)
1328 struct ctdb_statistics
*stats
;
1332 usage("statistics");
1335 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1336 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1341 if (options
.machinereadable
) {
1342 print_statistics_machine(stats
, true);
1344 print_statistics(stats
);
1350 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1351 struct ctdb_context
*ctdb
,
1352 int argc
, const char **argv
)
1357 usage("statisticsreset");
1360 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1361 ctdb
->cmd_pnn
, TIMEOUT());
1369 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1370 int argc
, const char **argv
)
1372 struct ctdb_statistics_list
*slist
;
1373 int ret
, count
= 0, i
;
1374 bool show_header
= true;
1381 count
= atoi(argv
[0]);
1384 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1385 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1390 for (i
=0; i
<slist
->num
; i
++) {
1391 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1394 if (options
.machinereadable
== 1) {
1395 print_statistics_machine(&slist
->stats
[i
],
1397 show_header
= false;
1399 print_statistics(&slist
->stats
[i
]);
1401 if (count
> 0 && i
== count
) {
1409 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1411 const struct ctdb_public_ip
*ip_a
= a
;
1412 const struct ctdb_public_ip
*ip_b
= b
;
1414 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1417 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1418 struct ctdb_public_ip_list
*ips
,
1419 struct ctdb_public_ip_info
**ipinfo
,
1423 char *conf
, *avail
, *active
;
1425 if (options
.machinereadable
== 1) {
1426 printf("%s%s%s%s%s", options
.sep
,
1427 "Public IP", options
.sep
,
1428 "Node", options
.sep
);
1429 if (options
.verbose
== 1) {
1430 printf("%s%s%s%s%s%s\n",
1431 "ActiveInterfaces", options
.sep
,
1432 "AvailableInterfaces", options
.sep
,
1433 "ConfiguredInterfaces", options
.sep
);
1439 printf("Public IPs on ALL nodes\n");
1441 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1445 for (i
= 0; i
< ips
->num
; i
++) {
1447 if (options
.machinereadable
== 1) {
1448 printf("%s%s%s%d%s", options
.sep
,
1449 ctdb_sock_addr_to_string(
1450 mem_ctx
, &ips
->ip
[i
].addr
),
1452 (int)ips
->ip
[i
].pnn
, options
.sep
);
1454 printf("%s", ctdb_sock_addr_to_string(
1455 mem_ctx
, &ips
->ip
[i
].addr
));
1458 if (options
.verbose
== 0) {
1459 if (options
.machinereadable
== 1) {
1462 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1471 if (ipinfo
[i
] == NULL
) {
1475 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1476 struct ctdb_iface
*iface
;
1478 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1480 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1482 conf
= talloc_asprintf_append(
1483 conf
, ",%s", iface
->name
);
1486 if (ipinfo
[i
]->active_idx
== j
) {
1487 active
= iface
->name
;
1490 if (iface
->link_state
== 0) {
1494 if (avail
== NULL
) {
1495 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1497 avail
= talloc_asprintf_append(
1498 avail
, ",%s", iface
->name
);
1504 if (options
.machinereadable
== 1) {
1505 printf("%s%s%s%s%s%s\n",
1506 active
? active
: "", options
.sep
,
1507 avail
? avail
: "", options
.sep
,
1508 conf
? conf
: "", options
.sep
);
1510 printf(" node[%d] active[%s] available[%s]"
1511 " configured[%s]\n",
1512 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1513 avail
? avail
: "", conf
? conf
: "");
1518 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1519 size_t datalen
, void *private_data
)
1521 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1522 private_data
, struct ctdb_public_ip_list
);
1523 struct ctdb_public_ip
*ip
;
1525 ip
= (struct ctdb_public_ip
*)databuf
;
1526 ips
->ip
[ips
->num
] = *ip
;
1532 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1533 struct ctdb_public_ip_list
**out
)
1535 struct ctdb_node_map
*nodemap
;
1536 struct ctdb_public_ip_list
*ips
;
1537 struct db_hash_context
*ipdb
;
1539 int ret
, count
, i
, j
;
1541 nodemap
= get_nodemap(ctdb
, false);
1542 if (nodemap
== NULL
) {
1546 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1551 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1557 for (i
=0; i
<count
; i
++) {
1558 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1559 pnn_list
[i
], TIMEOUT(),
1565 for (j
=0; j
<ips
->num
; j
++) {
1566 struct ctdb_public_ip ip
;
1568 ip
.pnn
= ips
->ip
[j
].pnn
;
1569 ip
.addr
= ips
->ip
[j
].addr
;
1571 if (pnn_list
[i
] == ip
.pnn
) {
1572 /* Node claims IP is hosted on it, so
1573 * save that information
1575 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1577 (uint8_t *)&ip
, sizeof(ip
));
1582 /* Node thinks IP is hosted elsewhere,
1583 * so overwrite with CTDB_UNKNOWN_PNN
1584 * if there's no existing entry
1586 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1588 if (ret
== ENOENT
) {
1589 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1590 ret
= db_hash_add(ipdb
,
1591 (uint8_t *)&ip
.addr
,
1605 talloc_free(pnn_list
);
1607 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1612 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1617 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1618 if (ips
->ip
== NULL
) {
1622 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1627 if (count
!= ips
->num
) {
1641 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1642 int argc
, const char **argv
)
1644 struct ctdb_public_ip_list
*ips
;
1645 struct ctdb_public_ip_info
**ipinfo
;
1647 bool do_all
= false;
1654 if (strcmp(argv
[0], "all") == 0) {
1662 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1664 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1665 ctdb
->cmd_pnn
, TIMEOUT(),
1672 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1673 ctdb_public_ip_cmp
);
1675 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1676 if (ipinfo
== NULL
) {
1680 for (i
=0; i
<ips
->num
; i
++) {
1683 pnn
= ips
->ip
[i
].pnn
;
1685 pnn
= ctdb
->cmd_pnn
;
1687 if (pnn
== CTDB_UNKNOWN_PNN
) {
1691 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1693 TIMEOUT(), &ips
->ip
[i
].addr
,
1700 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1704 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1705 int argc
, const char **argv
)
1707 struct ctdb_public_ip_info
*ipinfo
;
1708 ctdb_sock_addr addr
;
1715 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
1716 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1720 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1721 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1725 printf("Node %u does not know about IP %s\n",
1726 ctdb
->cmd_pnn
, argv
[0]);
1731 printf("Public IP[%s] info on node %u\n",
1732 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
),
1735 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1736 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
),
1737 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1739 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1740 struct ctdb_iface
*iface
;
1742 iface
= &ipinfo
->ifaces
->iface
[i
];
1743 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1744 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1746 iface
->link_state
== 0 ? "down" : "up",
1748 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1754 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1755 int argc
, const char **argv
)
1757 struct ctdb_iface_list
*ifaces
;
1764 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1765 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1770 if (ifaces
->num
== 0) {
1771 printf("No interfaces configured on node %u\n",
1776 if (options
.machinereadable
) {
1777 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1778 "Name", options
.sep
,
1779 "LinkStatus", options
.sep
,
1780 "References", options
.sep
);
1782 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1785 for (i
=0; i
<ifaces
->num
; i
++) {
1786 if (options
.machinereadable
) {
1787 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1788 ifaces
->iface
[i
].name
, options
.sep
,
1789 ifaces
->iface
[i
].link_state
, options
.sep
,
1790 ifaces
->iface
[i
].references
, options
.sep
);
1792 printf("name:%s link:%s references:%u\n",
1793 ifaces
->iface
[i
].name
,
1794 ifaces
->iface
[i
].link_state
? "up" : "down",
1795 ifaces
->iface
[i
].references
);
1802 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1803 int argc
, const char **argv
)
1805 struct ctdb_iface_list
*ifaces
;
1806 struct ctdb_iface
*iface
;
1810 usage("setifacelink");
1813 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1814 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1818 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1819 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1822 "Failed to get interface information from node %u\n",
1828 for (i
=0; i
<ifaces
->num
; i
++) {
1829 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1830 iface
= &ifaces
->iface
[i
];
1835 if (iface
== NULL
) {
1836 printf("Interface %s not configured on node %u\n",
1837 argv
[0], ctdb
->cmd_pnn
);
1841 if (strcmp(argv
[1], "up") == 0) {
1842 iface
->link_state
= 1;
1843 } else if (strcmp(argv
[1], "down") == 0) {
1844 iface
->link_state
= 0;
1846 usage("setifacelink");
1850 iface
->references
= 0;
1852 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1853 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1861 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1862 struct ctdb_context
*ctdb
,
1863 int argc
, const char **argv
)
1869 usage("process-exists");
1872 pid
= atoi(argv
[0]);
1873 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1874 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1880 printf("PID %u exists\n", pid
);
1882 printf("PID %u does not exist\n", pid
);
1887 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1888 int argc
, const char **argv
)
1890 struct ctdb_dbid_map
*dbmap
;
1897 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1898 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1903 if (options
.machinereadable
== 1) {
1904 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1907 "Name", options
.sep
,
1908 "Path", options
.sep
,
1909 "Persistent", options
.sep
,
1910 "Sticky", options
.sep
,
1911 "Unhealthy", options
.sep
,
1912 "Readonly", options
.sep
);
1914 printf("Number of databases:%d\n", dbmap
->num
);
1917 for (i
=0; i
<dbmap
->num
; i
++) {
1926 db_id
= dbmap
->dbs
[i
].db_id
;
1928 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1929 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1935 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1936 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1942 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1943 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1949 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
1950 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
1951 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
1953 if (options
.machinereadable
== 1) {
1954 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s\n",
1959 !! (persistent
), options
.sep
,
1960 !! (sticky
), options
.sep
,
1961 !! (health
), options
.sep
,
1962 !! (readonly
), options
.sep
);
1964 printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
1966 persistent
? " PERSISTENT" : "",
1967 sticky
? " STICKY" : "",
1968 readonly
? " READONLY" : "",
1969 health
? " UNHEALTHY" : "");
1972 talloc_free(discard_const(name
));
1973 talloc_free(discard_const(path
));
1974 talloc_free(discard_const(health
));
1980 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1981 int argc
, const char **argv
)
1984 const char *db_name
, *db_path
, *db_health
;
1989 usage("getdbstatus");
1992 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
1996 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1997 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2003 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2004 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2010 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2011 printf("PERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
2012 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2013 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2014 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"),
2015 (db_health
? db_health
: "OK"));
2019 struct dump_record_state
{
2023 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2025 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2029 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2030 for (i
=0; i
<val
.dsize
; i
++) {
2031 if (ISASCII(val
.dptr
[i
])) {
2032 fprintf(stdout
, "%c", val
.dptr
[i
]);
2034 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2037 fprintf(stdout
, "\"\n");
2040 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2042 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2043 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2044 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2045 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2046 fprintf(stdout
, " MIGRATED_WITH_DATA");
2048 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2049 fprintf(stdout
, " VACUUM_MIGRATED");
2051 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2052 fprintf(stdout
, " AUTOMATIC");
2054 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2055 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2057 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2058 fprintf(stdout
, " RO_HAVE_READONLY");
2060 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2061 fprintf(stdout
, " RO_REVOKING_READONLY");
2063 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2064 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2066 fprintf(stdout
, "\n");
2070 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2071 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2073 struct dump_record_state
*state
=
2074 (struct dump_record_state
*)private_data
;
2078 dump_tdb_data("key", key
);
2079 dump_ltdb_header(header
);
2080 dump_tdb_data("data", data
);
2081 fprintf(stdout
, "\n");
2086 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2087 int argc
, const char **argv
)
2089 struct ctdb_db_context
*db
;
2090 const char *db_name
;
2093 struct dump_record_state state
;
2100 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2104 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2107 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2113 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2114 ctdb
->cmd_pnn
, TIMEOUT(),
2115 dump_record
, &state
);
2117 printf("Dumped %u records\n", state
.count
);
2122 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2123 int argc
, const char **argv
)
2125 struct ctdb_db_context
*db
;
2126 const char *db_name
;
2129 struct dump_record_state state
;
2136 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2140 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2143 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2148 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2150 printf("Dumped %u record(s)\n", state
.count
);
2155 static int control_getmonmode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2156 int argc
, const char **argv
)
2161 usage("getmonmode");
2164 ret
= ctdb_ctrl_get_monmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2165 ctdb
->cmd_pnn
, TIMEOUT(), &mode
);
2171 (mode
== CTDB_MONITORING_ENABLED
) ? "ENABLED" : "DISABLED");
2175 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2176 struct ctdb_context
*ctdb
,
2177 int argc
, const char **argv
)
2183 usage("getcapabilities");
2186 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2187 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2192 if (options
.machinereadable
== 1) {
2193 printf("%s%s%s%s%s\n",
2195 "RECMASTER", options
.sep
,
2196 "LMASTER", options
.sep
);
2197 printf("%s%d%s%d%s\n", options
.sep
,
2198 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2199 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2201 printf("RECMASTER: %s\n",
2202 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2203 printf("LMASTER: %s\n",
2204 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2210 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2211 int argc
, const char **argv
)
2213 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2217 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2218 int argc
, const char **argv
)
2220 char *t
, *lvs_helper
= NULL
;
2226 t
= getenv("CTDB_LVS_HELPER");
2228 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2230 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2231 CTDB_HELPER_BINDIR
);
2234 if (lvs_helper
== NULL
) {
2235 fprintf(stderr
, "Unable to set LVS helper\n");
2239 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2242 static int control_disable_monitor(TALLOC_CTX
*mem_ctx
,
2243 struct ctdb_context
*ctdb
,
2244 int argc
, const char **argv
)
2249 usage("disablemonitor");
2252 ret
= ctdb_ctrl_disable_monitor(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2253 ctdb
->cmd_pnn
, TIMEOUT());
2261 static int control_enable_monitor(TALLOC_CTX
*mem_ctx
,
2262 struct ctdb_context
*ctdb
,
2263 int argc
, const char **argv
)
2268 usage("enablemonitor");
2271 ret
= ctdb_ctrl_enable_monitor(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2272 ctdb
->cmd_pnn
, TIMEOUT());
2280 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2281 int argc
, const char **argv
)
2291 found
= debug_level_parse(argv
[0], &log_level
);
2294 "Invalid debug level '%s'. Valid levels are:\n",
2296 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2300 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2301 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2309 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2310 int argc
, const char **argv
)
2313 const char *log_str
;
2320 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2321 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2326 log_str
= debug_level_to_string(loglevel
);
2327 printf("%s\n", log_str
);
2332 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2333 int argc
, const char **argv
)
2335 const char *db_name
;
2336 uint8_t db_flags
= 0;
2339 if (argc
< 1 || argc
> 2) {
2345 if (strcmp(argv
[1], "persistent") == 0) {
2346 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2347 } else if (strcmp(argv
[1], "readonly") == 0) {
2348 db_flags
= CTDB_DB_FLAGS_READONLY
;
2349 } else if (strcmp(argv
[1], "sticky") == 0) {
2350 db_flags
= CTDB_DB_FLAGS_STICKY
;
2356 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2365 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2366 int argc
, const char **argv
)
2368 const char *db_name
;
2371 struct ctdb_node_map
*nodemap
;
2379 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2380 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2385 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2386 fprintf(stderr
, "Database cannot be detached"
2387 " when recovery is active\n");
2391 nodemap
= get_nodemap(ctdb
, false);
2392 if (nodemap
== NULL
) {
2396 for (i
=0; i
<nodemap
->num
; i
++) {
2399 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
2402 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
2405 if (nodemap
->node
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2406 fprintf(stderr
, "Database cannot be detached on"
2407 " inactive (stopped or banned) node %u\n",
2408 nodemap
->node
[i
].pnn
);
2412 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2413 nodemap
->node
[i
].pnn
, TIMEOUT(),
2414 "AllowClientDBAttach", &value
);
2417 "Unable to get tunable AllowClientDBAttach"
2418 " from node %u\n", nodemap
->node
[i
].pnn
);
2424 "Database access is still active on node %u."
2425 " Set AllowclientDBAttach=0 on all nodes.\n",
2426 nodemap
->node
[i
].pnn
);
2432 for (i
=0; i
<argc
; i
++) {
2433 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2438 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
2440 "Persistent database %s cannot be detached\n",
2445 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2447 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2455 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2456 int argc
, const char **argv
)
2458 const char *mem_str
;
2462 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2463 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2468 n
= write(1, mem_str
, strlen(mem_str
)+1);
2469 if (n
< 0 || n
!= strlen(mem_str
)+1) {
2470 fprintf(stderr
, "Failed to write talloc summary\n");
2477 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2479 bool *done
= (bool *)private_data
;
2482 n
= write(1, data
.dptr
, data
.dsize
);
2483 if (n
< 0 || n
!= data
.dsize
) {
2484 fprintf(stderr
, "Failed to write talloc summary\n");
2490 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2491 int argc
, const char **argv
)
2493 struct ctdb_srvid_message msg
= { 0 };
2497 msg
.pnn
= ctdb
->pnn
;
2498 msg
.srvid
= next_srvid(ctdb
);
2500 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2501 msg
.srvid
, dump_memory
, &done
);
2506 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2507 ctdb
->cmd_pnn
, &msg
);
2512 ctdb_client_wait(ctdb
->ev
, &done
);
2516 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2517 int argc
, const char **argv
)
2522 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2523 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2528 printf("%u\n", pid
);
2532 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2533 const char *desc
, uint32_t flag
, bool set_flag
)
2535 struct ctdb_node_map
*nodemap
;
2538 nodemap
= get_nodemap(ctdb
, false);
2539 if (nodemap
== NULL
) {
2543 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2544 if (set_flag
== flag_is_set
) {
2546 fprintf(stderr
, "Node %u is already %s\n",
2547 ctdb
->cmd_pnn
, desc
);
2549 fprintf(stderr
, "Node %u is not %s\n",
2550 ctdb
->cmd_pnn
, desc
);
2558 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2559 uint32_t flag
, bool set_flag
)
2561 struct ctdb_node_map
*nodemap
;
2565 nodemap
= get_nodemap(ctdb
, true);
2566 if (nodemap
== NULL
) {
2568 "Failed to get nodemap, trying again\n");
2573 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2574 if (flag_is_set
== set_flag
) {
2582 static int ctdb_ctrl_modflags(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
2583 struct ctdb_client_context
*client
,
2584 uint32_t destnode
, struct timeval timeout
,
2585 uint32_t set
, uint32_t clear
)
2587 struct ctdb_node_map
*nodemap
;
2588 struct ctdb_node_flag_change flag_change
;
2589 struct ctdb_req_control request
;
2593 ret
= ctdb_ctrl_get_nodemap(mem_ctx
, ev
, client
, destnode
,
2594 tevent_timeval_zero(), &nodemap
);
2599 flag_change
.pnn
= destnode
;
2600 flag_change
.old_flags
= nodemap
->node
[destnode
].flags
;
2601 flag_change
.new_flags
= flag_change
.old_flags
| set
;
2602 flag_change
.new_flags
&= ~clear
;
2604 count
= list_of_connected_nodes(nodemap
, -1, mem_ctx
, &pnn_list
);
2609 ctdb_req_control_modify_flags(&request
, &flag_change
);
2610 ret
= ctdb_client_control_multi(mem_ctx
, ev
, client
, pnn_list
, count
,
2611 tevent_timeval_zero(), &request
,
2616 struct ipreallocate_state
{
2621 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2624 struct ipreallocate_state
*state
=
2625 (struct ipreallocate_state
*)private_data
;
2627 if (data
.dsize
!= sizeof(int)) {
2632 state
->status
= *(int *)data
.dptr
;
2636 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2638 struct ctdb_srvid_message msg
= { 0 };
2639 struct ipreallocate_state state
;
2642 msg
.pnn
= ctdb
->pnn
;
2643 msg
.srvid
= next_srvid(ctdb
);
2646 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2648 ipreallocate_handler
, &state
);
2654 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2656 CTDB_BROADCAST_CONNECTED
,
2662 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2668 if (state
.status
>= 0) {
2677 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2682 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2683 int argc
, const char **argv
)
2691 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2692 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2697 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2698 ctdb
->cmd_pnn
, TIMEOUT(),
2699 NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2702 "Failed to set DISABLED flag on node %u\n",
2707 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2708 return ipreallocate(mem_ctx
, ctdb
);
2711 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2712 int argc
, const char **argv
)
2720 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2721 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2726 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2727 ctdb
->cmd_pnn
, TIMEOUT(),
2728 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2730 fprintf(stderr
, "Failed to reset DISABLED flag on node %u\n",
2735 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2736 return ipreallocate(mem_ctx
, ctdb
);
2739 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2740 int argc
, const char **argv
)
2748 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2749 NODE_FLAGS_STOPPED
, true);
2754 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2755 ctdb
->cmd_pnn
, TIMEOUT());
2757 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2761 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2762 return ipreallocate(mem_ctx
, ctdb
);
2765 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2766 int argc
, const char **argv
)
2774 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2775 NODE_FLAGS_STOPPED
, false);
2780 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2781 ctdb
->cmd_pnn
, TIMEOUT());
2783 fprintf(stderr
, "Failed to continue stopped node %u\n",
2788 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2789 return ipreallocate(mem_ctx
, ctdb
);
2792 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2793 int argc
, const char **argv
)
2795 struct ctdb_ban_state ban_state
;
2802 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2803 NODE_FLAGS_BANNED
, true);
2808 ban_state
.pnn
= ctdb
->cmd_pnn
;
2809 ban_state
.time
= strtoul(argv
[0], NULL
, 0);
2811 if (ban_state
.time
== 0) {
2812 fprintf(stderr
, "Ban time cannot be zero\n");
2816 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2817 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2819 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2823 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2824 return ipreallocate(mem_ctx
, ctdb
);
2828 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2829 int argc
, const char **argv
)
2831 struct ctdb_ban_state ban_state
;
2838 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2839 NODE_FLAGS_BANNED
, false);
2844 ban_state
.pnn
= ctdb
->cmd_pnn
;
2847 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2848 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2850 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2854 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2855 return ipreallocate(mem_ctx
, ctdb
);
2859 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2860 int argc
, const char **argv
)
2868 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2869 ctdb
->cmd_pnn
, TIMEOUT());
2871 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2878 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2879 uint32_t *generation
)
2883 struct ctdb_vnn_map
*vnnmap
;
2887 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2888 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2890 fprintf(stderr
, "Failed to find recovery master\n");
2894 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2895 recmaster
, TIMEOUT(), &recmode
);
2897 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2902 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2907 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2908 recmaster
, TIMEOUT(), &vnnmap
);
2910 fprintf(stderr
, "Failed to get generation from node %u\n",
2915 if (vnnmap
->generation
== INVALID_GENERATION
) {
2916 talloc_free(vnnmap
);
2921 *generation
= vnnmap
->generation
;
2922 talloc_free(vnnmap
);
2927 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2928 int argc
, const char **argv
)
2930 uint32_t generation
, next_generation
;
2937 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2942 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2943 ctdb
->cmd_pnn
, TIMEOUT(),
2944 CTDB_RECOVERY_ACTIVE
);
2946 fprintf(stderr
, "Failed to set recovery mode active\n");
2951 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2954 "Failed to confirm end of recovery\n");
2958 if (next_generation
!= generation
) {
2968 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2969 int argc
, const char **argv
)
2972 usage("ipreallocate");
2975 return ipreallocate(mem_ctx
, ctdb
);
2978 static int control_isnotrecmaster(TALLOC_CTX
*mem_ctx
,
2979 struct ctdb_context
*ctdb
,
2980 int argc
, const char **argv
)
2986 usage("isnotrecmaster");
2989 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2990 ctdb
->pnn
, TIMEOUT(), &recmaster
);
2992 fprintf(stderr
, "Failed to get recmaster\n");
2996 if (recmaster
!= ctdb
->pnn
) {
2997 printf("this node is not the recmaster\n");
3001 printf("this node is the recmaster\n");
3005 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3006 int argc
, const char **argv
)
3008 struct ctdb_addr_info addr_info
;
3015 if (! parse_ip(argv
[0], NULL
, 0, &addr_info
.addr
)) {
3016 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3019 addr_info
.iface
= argv
[1];
3021 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3022 ctdb
->cmd_pnn
, TIMEOUT(),
3025 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3033 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3034 int argc
, const char **argv
)
3036 ctdb_sock_addr src
, dst
;
3039 if (argc
!= 0 && argc
!= 2) {
3044 struct ctdb_connection
*clist
;
3048 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3054 for (i
=0; i
<count
; i
++) {
3055 ret
= ctdb_sys_send_tcp(&clist
[i
].src
,
3065 if (num_failed
> 0) {
3066 fprintf(stderr
, "Failed to send %d tickles\n",
3075 if (! parse_ip_port(argv
[0], &src
)) {
3076 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3080 if (! parse_ip_port(argv
[1], &dst
)) {
3081 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3085 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3087 fprintf(stderr
, "Failed to send tickle ack\n");
3094 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3095 int argc
, const char **argv
)
3097 ctdb_sock_addr addr
;
3098 struct ctdb_tickle_list
*tickles
;
3102 if (argc
< 1 || argc
> 2) {
3103 usage("gettickles");
3107 port
= strtoul(argv
[1], NULL
, 10);
3110 if (! parse_ip(argv
[0], NULL
, port
, &addr
)) {
3111 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3115 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3116 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3119 fprintf(stderr
, "Failed to get list of connections\n");
3123 if (options
.machinereadable
) {
3124 printf("%s%s%s%s%s%s%s%s%s\n",
3126 "Source IP", options
.sep
,
3127 "Port", options
.sep
,
3128 "Destiation IP", options
.sep
,
3129 "Port", options
.sep
);
3130 for (i
=0; i
<tickles
->num
; i
++) {
3131 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3132 ctdb_sock_addr_to_string(
3133 mem_ctx
, &tickles
->conn
[i
].src
),
3135 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3137 ctdb_sock_addr_to_string(
3138 mem_ctx
, &tickles
->conn
[i
].dst
),
3140 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3144 printf("Connections for IP: %s\n",
3145 ctdb_sock_addr_to_string(mem_ctx
, &tickles
->addr
));
3146 printf("Num connections: %u\n", tickles
->num
);
3147 for (i
=0; i
<tickles
->num
; i
++) {
3148 printf("SRC: %s:%u DST: %s:%u\n",
3149 ctdb_sock_addr_to_string(
3150 mem_ctx
, &tickles
->conn
[i
].src
),
3151 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3152 ctdb_sock_addr_to_string(
3153 mem_ctx
, &tickles
->conn
[i
].dst
),
3154 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
));
3158 talloc_free(tickles
);
3162 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3163 struct ctdb_connection
*conn
);
3165 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3167 struct process_clist_state
{
3168 struct ctdb_connection
*clist
;
3170 int num_failed
, num_total
;
3171 clist_reply_func reply_func
;
3174 static void process_clist_done(struct tevent_req
*subreq
);
3176 static struct tevent_req
*process_clist_send(
3177 TALLOC_CTX
*mem_ctx
,
3178 struct ctdb_context
*ctdb
,
3179 struct ctdb_connection
*clist
,
3181 clist_request_func request_func
,
3182 clist_reply_func reply_func
)
3184 struct tevent_req
*req
, *subreq
;
3185 struct process_clist_state
*state
;
3186 struct ctdb_req_control request
;
3189 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3194 state
->clist
= clist
;
3195 state
->count
= count
;
3196 state
->reply_func
= reply_func
;
3198 for (i
=0; i
<count
; i
++) {
3199 request_func(&request
, &clist
[i
]);
3200 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3201 ctdb
->client
, ctdb
->cmd_pnn
,
3202 TIMEOUT(), &request
);
3203 if (tevent_req_nomem(subreq
, req
)) {
3204 return tevent_req_post(req
, ctdb
->ev
);
3206 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3212 static void process_clist_done(struct tevent_req
*subreq
)
3214 struct tevent_req
*req
= tevent_req_callback_data(
3215 subreq
, struct tevent_req
);
3216 struct process_clist_state
*state
= tevent_req_data(
3217 req
, struct process_clist_state
);
3218 struct ctdb_reply_control
*reply
;
3222 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3223 TALLOC_FREE(subreq
);
3225 state
->num_failed
+= 1;
3229 ret
= state
->reply_func(reply
);
3231 state
->num_failed
+= 1;
3236 state
->num_total
+= 1;
3237 if (state
->num_total
== state
->count
) {
3238 tevent_req_done(req
);
3242 static int process_clist_recv(struct tevent_req
*req
)
3244 struct process_clist_state
*state
= tevent_req_data(
3245 req
, struct process_clist_state
);
3247 return state
->num_failed
;
3250 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3251 int argc
, const char **argv
)
3253 struct ctdb_connection conn
;
3256 if (argc
!= 0 && argc
!= 2) {
3261 struct ctdb_connection
*clist
;
3262 struct tevent_req
*req
;
3265 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3273 req
= process_clist_send(mem_ctx
, ctdb
, clist
, count
,
3274 ctdb_req_control_tcp_add_delayed_update
,
3275 ctdb_reply_control_tcp_add_delayed_update
);
3281 tevent_req_poll(req
, ctdb
->ev
);
3284 ret
= process_clist_recv(req
);
3286 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3293 if (! parse_ip_port(argv
[0], &conn
.src
)) {
3294 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3297 if (! parse_ip_port(argv
[1], &conn
.dst
)) {
3298 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3302 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3303 ctdb
->client
, ctdb
->cmd_pnn
,
3306 fprintf(stderr
, "Failed to register connection\n");
3313 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3314 int argc
, const char **argv
)
3316 struct ctdb_connection conn
;
3319 if (argc
!= 0 && argc
!= 2) {
3324 struct ctdb_connection
*clist
;
3325 struct tevent_req
*req
;
3328 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3336 req
= process_clist_send(mem_ctx
, ctdb
, clist
, count
,
3337 ctdb_req_control_tcp_remove
,
3338 ctdb_reply_control_tcp_remove
);
3344 tevent_req_poll(req
, ctdb
->ev
);
3347 ret
= process_clist_recv(req
);
3349 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3356 if (! parse_ip_port(argv
[0], &conn
.src
)) {
3357 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3360 if (! parse_ip_port(argv
[1], &conn
.dst
)) {
3361 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3365 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3366 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3368 fprintf(stderr
, "Failed to unregister connection\n");
3375 static int control_check_srvids(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3376 int argc
, const char **argv
)
3383 usage("check_srvids");
3386 srvid
= talloc_array(mem_ctx
, uint64_t, argc
);
3387 if (srvid
== NULL
) {
3388 fprintf(stderr
, "Memory allocation error\n");
3392 for (i
=0; i
<argc
; i
++) {
3393 srvid
[i
] = strtoull(argv
[i
], NULL
, 0);
3396 ret
= ctdb_ctrl_check_srvids(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3397 ctdb
->cmd_pnn
, TIMEOUT(), srvid
, argc
,
3400 fprintf(stderr
, "Failed to check srvids on node %u\n",
3405 for (i
=0; i
<argc
; i
++) {
3406 printf("SRVID 0x%" PRIx64
" %s\n", srvid
[i
],
3407 (result
[i
] ? "exists" : "does not exist"));
3413 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3414 int argc
, const char **argv
)
3416 struct ctdb_node_map
*nodemap
;
3423 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3424 if (nodemap
== NULL
) {
3428 for (i
=0; i
<nodemap
->num
; i
++) {
3429 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3433 if (options
.machinereadable
) {
3434 printf("%s%u%s%s%s\n", options
.sep
,
3435 nodemap
->node
[i
].pnn
, options
.sep
,
3436 ctdb_sock_addr_to_string(
3437 mem_ctx
, &nodemap
->node
[i
].addr
),
3441 ctdb_sock_addr_to_string(
3442 mem_ctx
, &nodemap
->node
[i
].addr
));
3449 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3450 struct ctdb_node_map
*nodemap2
)
3454 if (nodemap1
->num
!= nodemap2
->num
) {
3458 for (i
=0; i
<nodemap1
->num
; i
++) {
3459 struct ctdb_node_and_flags
*n1
, *n2
;
3461 n1
= &nodemap1
->node
[i
];
3462 n2
= &nodemap2
->node
[i
];
3464 if ((n1
->pnn
!= n2
->pnn
) ||
3465 (n1
->flags
!= n2
->flags
) ||
3466 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3474 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3475 struct ctdb_node_map
*nm
,
3476 struct ctdb_node_map
*fnm
,
3480 bool check_failed
= false;
3484 for (i
=0; i
<nm
->num
; i
++) {
3485 if (i
>= fnm
->num
) {
3487 "Node %u (%s) missing from nodes file\n",
3489 ctdb_sock_addr_to_string(
3490 mem_ctx
, &nm
->node
[i
].addr
));
3491 check_failed
= true;
3494 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3495 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3496 /* Node remains deleted */
3500 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3501 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3502 /* Node not newly nor previously deleted */
3503 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3504 &fnm
->node
[i
].addr
)) {
3506 "Node %u has changed IP address"
3507 " (was %s, now %s)\n",
3509 ctdb_sock_addr_to_string(
3510 mem_ctx
, &nm
->node
[i
].addr
),
3511 ctdb_sock_addr_to_string(
3512 mem_ctx
, &fnm
->node
[i
].addr
));
3513 check_failed
= true;
3515 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3517 "WARNING: Node %u is disconnected."
3518 " You MUST fix this node manually!\n",
3525 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3526 /* Node is being deleted */
3527 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3529 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3531 "ERROR: Node %u is still connected\n",
3533 check_failed
= true;
3538 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3539 /* Node was previously deleted */
3540 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3547 "ERROR: Nodes will not be reloaded due to previous error\n");
3551 /* Leftover nodes in file are NEW */
3552 for (; i
< fnm
->num
; i
++) {
3553 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3560 struct disable_recoveries_state
{
3568 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3571 struct disable_recoveries_state
*state
=
3572 (struct disable_recoveries_state
*)private_data
;
3575 if (data
.dsize
!= sizeof(int)) {
3580 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3581 ret
= *(int *)data
.dptr
;
3583 state
->status
= ret
;
3587 for (i
=0; i
<state
->node_count
; i
++) {
3588 if (state
->pnn_list
[i
] == ret
) {
3589 state
->reply
[i
] = true;
3595 for (i
=0; i
<state
->node_count
; i
++) {
3596 if (! state
->reply
[i
]) {
3597 state
->done
= false;
3603 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3604 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3606 struct ctdb_disable_message disable
= { 0 };
3607 struct disable_recoveries_state state
;
3610 disable
.pnn
= ctdb
->pnn
;
3611 disable
.srvid
= next_srvid(ctdb
);
3612 disable
.timeout
= timeout
;
3614 state
.pnn_list
= pnn_list
;
3615 state
.node_count
= count
;
3618 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3619 if (state
.reply
== NULL
) {
3623 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3625 disable_recoveries_handler
,
3631 for (i
=0; i
<count
; i
++) {
3632 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3641 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3643 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3645 ret
= (state
.status
>= 0 ? 0 : 1);
3649 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3650 disable
.srvid
, &state
);
3654 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3655 int argc
, const char **argv
)
3657 struct ctdb_node_map
*nodemap
= NULL
;
3658 struct ctdb_node_map
*file_nodemap
;
3659 struct ctdb_node_map
*remote_nodemap
;
3660 struct ctdb_req_control request
;
3661 struct ctdb_reply_control
**reply
;
3667 nodemap
= get_nodemap(ctdb
, false);
3668 if (nodemap
== NULL
) {
3672 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3673 if (file_nodemap
== NULL
) {
3677 for (i
=0; i
<nodemap
->num
; i
++) {
3678 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3682 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3683 nodemap
->node
[i
].pnn
, TIMEOUT(),
3687 "ERROR: Failed to get nodes file from node %u\n",
3688 nodemap
->node
[i
].pnn
);
3692 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3694 "ERROR: Nodes file on node %u differs"
3695 " from current node (%u)\n",
3696 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3701 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3707 fprintf(stderr
, "No change in nodes file,"
3708 " skipping unnecessary reload\n");
3712 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3713 mem_ctx
, &pnn_list
);
3715 fprintf(stderr
, "Memory allocation error\n");
3719 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3722 fprintf(stderr
, "Failed to disable recoveries\n");
3726 ctdb_req_control_reload_nodes_file(&request
);
3727 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3728 pnn_list
, count
, TIMEOUT(),
3729 &request
, NULL
, &reply
);
3731 bool failed
= false;
3733 for (i
=0; i
<count
; i
++) {
3734 ret
= ctdb_reply_control_reload_nodes_file(reply
[i
]);
3737 "Node %u failed to reload nodes\n",
3744 "You MUST fix failed nodes manually!\n");
3748 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3750 fprintf(stderr
, "Failed to enable recoveries\n");
3757 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3758 ctdb_sock_addr
*addr
, uint32_t pnn
)
3760 struct ctdb_public_ip_list
*pubip_list
;
3761 struct ctdb_public_ip pubip
;
3762 struct ctdb_node_map
*nodemap
;
3763 struct ctdb_req_control request
;
3767 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3768 CTDB_BROADCAST_CONNECTED
,
3769 2*options
.timelimit
);
3771 fprintf(stderr
, "Failed to disable IP check\n");
3775 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3776 pnn
, TIMEOUT(), false, &pubip_list
);
3778 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3783 for (i
=0; i
<pubip_list
->num
; i
++) {
3784 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3789 if (i
== pubip_list
->num
) {
3790 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3791 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
));
3795 nodemap
= get_nodemap(ctdb
, false);
3796 if (nodemap
== NULL
) {
3800 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3802 fprintf(stderr
, "Memory allocation error\n");
3808 ctdb_req_control_release_ip(&request
, &pubip
);
3810 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3811 pnn_list
, count
, TIMEOUT(),
3812 &request
, NULL
, NULL
);
3814 fprintf(stderr
, "Failed to release IP on nodes\n");
3818 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3819 pnn
, TIMEOUT(), &pubip
);
3821 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3828 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3829 int argc
, const char **argv
)
3831 ctdb_sock_addr addr
;
3833 int ret
, retries
= 0;
3839 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
3840 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3844 pnn
= strtoul(argv
[1], NULL
, 10);
3845 if (pnn
== CTDB_UNKNOWN_PNN
) {
3846 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3850 while (retries
< 5) {
3851 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3861 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3869 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3874 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3875 CTDB_BROADCAST_CONNECTED
, pnn
);
3878 "Failed to ask recovery master to distribute IPs\n");
3885 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3886 int argc
, const char **argv
)
3888 ctdb_sock_addr addr
;
3889 struct ctdb_public_ip_list
*pubip_list
;
3890 struct ctdb_addr_info addr_info
;
3892 int ret
, i
, retries
= 0;
3898 if (! parse_ip_mask(argv
[0], argv
[1], &addr
, &mask
)) {
3899 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3903 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3904 ctdb
->cmd_pnn
, TIMEOUT(),
3905 false, &pubip_list
);
3907 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3912 for (i
=0; i
<pubip_list
->num
; i
++) {
3913 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3914 fprintf(stderr
, "Node already knows about IP %s\n",
3915 ctdb_sock_addr_to_string(mem_ctx
, &addr
));
3920 addr_info
.addr
= addr
;
3921 addr_info
.mask
= mask
;
3922 addr_info
.iface
= argv
[1];
3924 while (retries
< 5) {
3925 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3926 ctdb
->cmd_pnn
, TIMEOUT(),
3937 fprintf(stderr
, "Failed to add public IP to node %u."
3938 " Giving up\n", ctdb
->cmd_pnn
);
3942 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3950 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3951 int argc
, const char **argv
)
3953 ctdb_sock_addr addr
;
3954 struct ctdb_public_ip_list
*pubip_list
;
3955 struct ctdb_addr_info addr_info
;
3962 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
3963 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3967 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3968 ctdb
->cmd_pnn
, TIMEOUT(),
3969 false, &pubip_list
);
3971 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3976 for (i
=0; i
<pubip_list
->num
; i
++) {
3977 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3982 if (i
== pubip_list
->num
) {
3983 fprintf(stderr
, "Node does not know about IP address %s\n",
3984 ctdb_sock_addr_to_string(mem_ctx
, &addr
));
3988 addr_info
.addr
= addr
;
3990 addr_info
.iface
= NULL
;
3992 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3993 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
3995 fprintf(stderr
, "Failed to delete public IP from node %u\n",
4003 #define DB_VERSION 3
4004 #define MAX_DB_NAME 64
4005 #define MAX_REC_BUFFER_SIZE (100*1000)
4008 unsigned long version
;
4010 unsigned long flags
;
4013 char name
[MAX_DB_NAME
];
4016 struct backup_state
{
4017 TALLOC_CTX
*mem_ctx
;
4018 struct ctdb_rec_buffer
*recbuf
;
4021 unsigned int nbuf
, nrec
;
4024 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
4025 TDB_DATA key
, TDB_DATA data
, void *private_data
)
4027 struct backup_state
*state
= (struct backup_state
*)private_data
;
4031 if (state
->recbuf
== NULL
) {
4032 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4034 if (state
->recbuf
== NULL
) {
4039 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4045 len
= ctdb_rec_buffer_len(state
->recbuf
);
4046 if (len
< MAX_REC_BUFFER_SIZE
) {
4050 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4052 fprintf(stderr
, "Failed to write records to backup file\n");
4057 state
->nrec
+= state
->recbuf
->count
;
4058 TALLOC_FREE(state
->recbuf
);
4063 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4064 int argc
, const char **argv
)
4066 const char *db_name
;
4067 struct ctdb_db_context
*db
;
4070 struct backup_state state
;
4071 struct db_header db_hdr
;
4078 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4082 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4085 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4089 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4092 fprintf(stderr
, "Failed to open file %s for writing\n",
4097 /* Write empty header first */
4098 ZERO_STRUCT(db_hdr
);
4099 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4103 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4107 state
.mem_ctx
= mem_ctx
;
4108 state
.recbuf
= NULL
;
4113 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4115 fprintf(stderr
, "Failed to collect records from DB %s\n",
4121 if (state
.recbuf
!= NULL
) {
4122 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4125 "Failed to write records to backup file\n");
4131 state
.nrec
+= state
.recbuf
->count
;
4132 TALLOC_FREE(state
.recbuf
);
4135 db_hdr
.version
= DB_VERSION
;
4136 db_hdr
.timestamp
= time(NULL
);
4137 db_hdr
.flags
= db_flags
;
4138 db_hdr
.nbuf
= state
.nbuf
;
4139 db_hdr
.nrec
= state
.nrec
;
4140 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4142 lseek(fd
, 0, SEEK_SET
);
4143 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4147 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4152 printf("Database backed up to %s\n", argv
[1]);
4156 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4157 int argc
, const char **argv
)
4159 const char *db_name
= NULL
;
4160 struct ctdb_db_context
*db
;
4161 struct db_header db_hdr
;
4162 struct ctdb_node_map
*nodemap
;
4163 struct ctdb_req_control request
;
4164 struct ctdb_reply_control
**reply
;
4165 struct ctdb_transdb wipedb
;
4166 struct ctdb_pulldb_ext pulldb
;
4167 struct ctdb_rec_buffer
*recbuf
;
4168 uint32_t generation
;
4174 if (argc
< 1 || argc
> 2) {
4178 fd
= open(argv
[0], O_RDONLY
, 0600);
4181 fprintf(stderr
, "Failed to open file %s for reading\n",
4190 ret
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4194 fprintf(stderr
, "Failed to read db header from file %s\n",
4198 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4200 if (db_hdr
.version
!= DB_VERSION
) {
4202 "Wrong version of backup file, expected %u, got %lu\n",
4203 DB_VERSION
, db_hdr
.version
);
4208 if (db_name
== NULL
) {
4209 db_name
= db_hdr
.name
;
4212 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4213 localtime(&db_hdr
.timestamp
));
4214 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4216 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4219 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4224 nodemap
= get_nodemap(ctdb
, false);
4225 if (nodemap
== NULL
) {
4226 fprintf(stderr
, "Failed to get nodemap\n");
4231 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4233 fprintf(stderr
, "Failed to get current generation\n");
4238 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4245 wipedb
.db_id
= ctdb_db_id(db
);
4246 wipedb
.tid
= generation
;
4248 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4249 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4250 ctdb
->client
, pnn_list
, count
,
4251 TIMEOUT(), &request
, NULL
, NULL
);
4257 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4258 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4259 pnn_list
, count
, TIMEOUT(),
4260 &request
, NULL
, NULL
);
4265 ctdb_req_control_wipe_database(&request
, &wipedb
);
4266 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4267 pnn_list
, count
, TIMEOUT(),
4268 &request
, NULL
, NULL
);
4273 pulldb
.db_id
= ctdb_db_id(db
);
4275 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4277 ctdb_req_control_db_push_start(&request
, &pulldb
);
4278 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4279 pnn_list
, count
, TIMEOUT(),
4280 &request
, NULL
, NULL
);
4285 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4286 struct ctdb_req_message message
;
4289 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4294 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4295 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4296 if (data
.dptr
== NULL
) {
4300 ctdb_rec_buffer_push(recbuf
, data
.dptr
);
4302 message
.srvid
= pulldb
.srvid
;
4303 message
.data
.data
= data
;
4305 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4313 talloc_free(recbuf
);
4314 talloc_free(data
.dptr
);
4317 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4318 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4319 pnn_list
, count
, TIMEOUT(),
4320 &request
, NULL
, &reply
);
4325 for (i
=0; i
<count
; i
++) {
4326 uint32_t num_records
;
4328 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4331 fprintf(stderr
, "Invalid response from node %u\n",
4336 if (num_records
!= db_hdr
.nrec
) {
4337 fprintf(stderr
, "Node %u received %u of %lu records\n",
4338 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4343 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4344 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4345 pnn_list
, count
, TIMEOUT(),
4346 &request
, NULL
, NULL
);
4351 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4352 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4353 pnn_list
, count
, TIMEOUT(),
4354 &request
, NULL
, NULL
);
4359 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4360 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4361 ctdb
->client
, pnn_list
, count
,
4362 TIMEOUT(), &request
, NULL
, NULL
);
4367 printf("Database %s restored\n", db_name
);
4374 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4375 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4379 struct dumpdbbackup_state
{
4380 ctdb_rec_parser_func_t parser
;
4381 struct dump_record_state sub_state
;
4384 static int dumpdbbackup_handler(uint32_t reqid
,
4385 struct ctdb_ltdb_header
*header
,
4386 TDB_DATA key
, TDB_DATA data
,
4389 struct dumpdbbackup_state
*state
=
4390 (struct dumpdbbackup_state
*)private_data
;
4391 struct ctdb_ltdb_header hdr
;
4394 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4399 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4402 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4403 int argc
, const char **argv
)
4405 struct db_header db_hdr
;
4407 struct dumpdbbackup_state state
;
4411 usage("dumpbackup");
4414 fd
= open(argv
[0], O_RDONLY
, 0600);
4417 fprintf(stderr
, "Failed to open file %s for reading\n",
4422 ret
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4426 fprintf(stderr
, "Failed to read db header from file %s\n",
4430 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4432 if (db_hdr
.version
!= DB_VERSION
) {
4434 "Wrong version of backup file, expected %u, got %lu\n",
4435 DB_VERSION
, db_hdr
.version
);
4440 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4441 localtime(&db_hdr
.timestamp
));
4442 printf("Dumping database %s from backup @ %s\n",
4443 db_hdr
.name
, timebuf
);
4445 state
.parser
= dump_record
;
4446 state
.sub_state
.count
= 0;
4448 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4449 struct ctdb_rec_buffer
*recbuf
;
4451 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4453 fprintf(stderr
, "Failed to read records\n");
4458 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4461 fprintf(stderr
, "Failed to dump records\n");
4468 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4472 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4473 int argc
, const char **argv
)
4475 const char *db_name
;
4476 struct ctdb_db_context
*db
;
4479 struct ctdb_node_map
*nodemap
;
4480 struct ctdb_req_control request
;
4481 struct ctdb_transdb wipedb
;
4482 uint32_t generation
;
4490 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4494 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4497 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4501 nodemap
= get_nodemap(ctdb
, false);
4502 if (nodemap
== NULL
) {
4503 fprintf(stderr
, "Failed to get nodemap\n");
4507 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4509 fprintf(stderr
, "Failed to get current generation\n");
4513 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4519 ctdb_req_control_db_freeze(&request
, db_id
);
4520 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4521 ctdb
->client
, pnn_list
, count
,
4522 TIMEOUT(), &request
, NULL
, NULL
);
4527 wipedb
.db_id
= db_id
;
4528 wipedb
.tid
= generation
;
4530 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4531 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4532 pnn_list
, count
, TIMEOUT(),
4533 &request
, NULL
, NULL
);
4538 ctdb_req_control_wipe_database(&request
, &wipedb
);
4539 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4540 pnn_list
, count
, TIMEOUT(),
4541 &request
, NULL
, NULL
);
4546 ctdb_req_control_db_set_healthy(&request
, db_id
);
4547 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4548 pnn_list
, count
, TIMEOUT(),
4549 &request
, NULL
, NULL
);
4554 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4555 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4556 pnn_list
, count
, TIMEOUT(),
4557 &request
, NULL
, NULL
);
4562 ctdb_req_control_db_thaw(&request
, db_id
);
4563 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4564 ctdb
->client
, pnn_list
, count
,
4565 TIMEOUT(), &request
, NULL
, NULL
);
4570 printf("Database %s wiped\n", db_name
);
4575 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4576 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4580 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4581 int argc
, const char **argv
)
4586 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4587 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4592 printf("%u\n", recmaster
);
4596 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4597 int argc
, const char **argv
)
4599 char *t
, *event_helper
= NULL
;
4600 char *eventd_socket
= NULL
;
4601 const char **new_argv
;
4604 t
= getenv("CTDB_EVENT_HELPER");
4606 event_helper
= talloc_strdup(mem_ctx
, t
);
4608 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_event",
4609 CTDB_HELPER_BINDIR
);
4612 if (event_helper
== NULL
) {
4613 fprintf(stderr
, "Unable to set event daemon helper\n");
4617 t
= getenv("CTDB_SOCKET");
4619 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4622 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4626 if (eventd_socket
== NULL
) {
4627 fprintf(stderr
, "Unable to set event daemon socket\n");
4631 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 1);
4632 if (new_argv
== NULL
) {
4633 fprintf(stderr
, "Memory allocation error\n");
4637 new_argv
[0] = eventd_socket
;
4638 for (i
=0; i
<argc
; i
++) {
4639 new_argv
[i
+1] = argv
[i
];
4642 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4646 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4647 int argc
, const char **argv
)
4649 const char *new_argv
[3];
4652 usage("scriptstatus");
4655 new_argv
[0] = "status";
4656 new_argv
[1] = (argc
== 0) ? "monitor" : argv
[0];
4659 (void) control_event(mem_ctx
, ctdb
, 2, new_argv
);
4663 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4664 int argc
, const char **argv
)
4666 char *t
, *natgw_helper
= NULL
;
4672 t
= getenv("CTDB_NATGW_HELPER");
4674 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4676 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4677 CTDB_HELPER_BINDIR
);
4680 if (natgw_helper
== NULL
) {
4681 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4685 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4689 static int control_natgwlist(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4690 int argc
, const char **argv
)
4692 char *t
, *natgw_helper
= NULL
;
4693 const char *cmd_argv
[] = { "natgwlist", NULL
};
4699 t
= getenv("CTDB_NATGW_HELPER");
4701 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4703 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4704 CTDB_HELPER_BINDIR
);
4707 if (natgw_helper
== NULL
) {
4708 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4712 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4717 * Find the PNN of the current node
4718 * discover the pnn by loading the nodes file and try to bind
4719 * to all addresses one at a time until the ip address is found.
4721 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4723 struct ctdb_node_map
*nodemap
;
4726 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4727 if (nodemap
== NULL
) {
4731 for (i
=0; i
<nodemap
->num
; i
++) {
4732 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4735 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4737 *pnn
= nodemap
->node
[i
].pnn
;
4739 talloc_free(nodemap
);
4744 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4745 talloc_free(nodemap
);
4749 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4750 int argc
, const char **argv
)
4752 const char *reclock
;
4756 usage("getreclock");
4759 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4760 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4765 if (reclock
!= NULL
) {
4766 printf("%s\n", reclock
);
4772 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4773 struct ctdb_context
*ctdb
,
4774 int argc
, const char **argv
)
4776 uint32_t lmasterrole
= 0;
4780 usage("setlmasterrole");
4783 if (strcmp(argv
[0], "on") == 0) {
4785 } else if (strcmp(argv
[0], "off") == 0) {
4788 usage("setlmasterrole");
4791 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4792 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4800 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4801 struct ctdb_context
*ctdb
,
4802 int argc
, const char **argv
)
4804 uint32_t recmasterrole
= 0;
4808 usage("setrecmasterrole");
4811 if (strcmp(argv
[0], "on") == 0) {
4813 } else if (strcmp(argv
[0], "off") == 0) {
4816 usage("setrecmasterrole");
4819 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4820 ctdb
->cmd_pnn
, TIMEOUT(),
4829 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4830 struct ctdb_context
*ctdb
,
4831 int argc
, const char **argv
)
4838 usage("setdbreadonly");
4841 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4845 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
4846 fprintf(stderr
, "Cannot set READONLY on persistent DB\n");
4850 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4851 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4859 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4860 int argc
, const char **argv
)
4867 usage("setdbsticky");
4870 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4874 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
4875 fprintf(stderr
, "Cannot set STICKY on persistent DB\n");
4879 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4880 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4888 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4889 int argc
, const char **argv
)
4891 const char *db_name
;
4892 struct ctdb_db_context
*db
;
4893 struct ctdb_transaction_handle
*h
;
4898 if (argc
< 2 || argc
> 3) {
4902 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4906 if (! (db_flags
& CTDB_DB_FLAGS_PERSISTENT
)) {
4907 fprintf(stderr
, "DB %s is not a persistent database\n",
4912 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4915 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4919 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4921 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4925 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4926 TIMEOUT(), db
, true, &h
);
4928 fprintf(stderr
, "Failed to start transaction on db %s\n",
4933 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4935 fprintf(stderr
, "Failed to read record for key %s\n",
4937 ctdb_transaction_cancel(h
);
4941 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4943 ctdb_transaction_cancel(h
);
4947 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4948 int argc
, const char **argv
)
4950 const char *db_name
;
4951 struct ctdb_db_context
*db
;
4952 struct ctdb_transaction_handle
*h
;
4961 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4965 if (! (db_flags
& CTDB_DB_FLAGS_PERSISTENT
)) {
4966 fprintf(stderr
, "DB %s is not a persistent database\n",
4971 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4974 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4978 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4980 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4984 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4986 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
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_store_record(h
, key
, data
);
5000 fprintf(stderr
, "Failed to store 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 control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5018 int argc
, const char **argv
)
5020 const char *db_name
;
5021 struct ctdb_db_context
*db
;
5022 struct ctdb_transaction_handle
*h
;
5031 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5035 if (! (db_flags
& CTDB_DB_FLAGS_PERSISTENT
)) {
5036 fprintf(stderr
, "DB %s is not a persistent database\n",
5041 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5044 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5048 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5050 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5054 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5055 TIMEOUT(), db
, false, &h
);
5057 fprintf(stderr
, "Failed to start transaction on db %s\n",
5062 ret
= ctdb_transaction_delete_record(h
, key
);
5064 fprintf(stderr
, "Failed to delete record for key %s\n",
5066 ctdb_transaction_cancel(h
);
5070 ret
= ctdb_transaction_commit(h
);
5072 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5074 ctdb_transaction_cancel(h
);
5081 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5089 /* Skip whitespace */
5090 n
= strspn(*ptr
, " \t");
5094 /* Quoted ASCII string - no wide characters! */
5096 n
= strcspn(t
, "\"");
5099 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5106 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5110 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5117 #define MAX_LINE_SIZE 1024
5119 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5120 TDB_DATA
*key
, TDB_DATA
*value
)
5122 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5126 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5132 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5133 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5134 /* Line Ignored but not EOF */
5140 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5142 /* Line Ignored but not EOF */
5143 talloc_free(key
->dptr
);
5151 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5152 int argc
, const char **argv
)
5154 const char *db_name
;
5155 struct ctdb_db_context
*db
;
5156 struct ctdb_transaction_handle
*h
;
5159 TDB_DATA key
, value
;
5162 if (argc
< 1 || argc
> 2) {
5166 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5170 if (! (db_flags
& CTDB_DB_FLAGS_PERSISTENT
)) {
5171 fprintf(stderr
, "DB %s is not a persistent database\n",
5177 file
= fopen(argv
[1], "r");
5179 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5186 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5189 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5193 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5194 TIMEOUT(), db
, false, &h
);
5196 fprintf(stderr
, "Failed to start transaction on db %s\n",
5201 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5202 if (key
.dsize
!= 0) {
5203 ret
= ctdb_transaction_store_record(h
, key
, value
);
5205 fprintf(stderr
, "Failed to store record\n");
5206 ctdb_transaction_cancel(h
);
5209 talloc_free(key
.dptr
);
5210 talloc_free(value
.dptr
);
5214 ret
= ctdb_transaction_commit(h
);
5216 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5218 ctdb_transaction_cancel(h
);
5222 if (file
!= stdin
) {
5228 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5229 int argc
, const char **argv
)
5231 struct tdb_context
*tdb
;
5233 struct ctdb_ltdb_header header
;
5236 if (argc
< 2 || argc
> 3) {
5240 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5242 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5246 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5248 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5253 data
= tdb_fetch(tdb
, key
);
5254 if (data
.dptr
== NULL
) {
5255 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5260 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5261 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5272 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5274 fprintf(stderr
, "Failed to open output file %s\n",
5279 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5280 if (nwritten
!= data
.dsize
) {
5281 fprintf(stderr
, "Failed to write record to file\n");
5290 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5292 fprintf(stderr
, "Failed to parse header from data\n");
5296 dump_ltdb_header(&header
);
5297 dump_tdb_data("data", data
);
5302 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5303 int argc
, const char **argv
)
5305 struct tdb_context
*tdb
;
5306 TDB_DATA key
, data
[2], value
;
5307 struct ctdb_ltdb_header header
;
5308 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5311 if (argc
< 3 || argc
> 5) {
5315 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5317 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5321 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5323 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5328 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5330 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5335 ZERO_STRUCT(header
);
5338 header
.rsn
= (uint64_t)strtoull(argv
[3], NULL
, 0);
5341 header
.dmaster
= (uint32_t)atol(argv
[4]);
5344 header
.flags
= (uint32_t)atol(argv
[5]);
5347 ctdb_ltdb_header_push(&header
, header_buf
);
5349 data
[0].dsize
= ctdb_ltdb_header_len(&header
);
5350 data
[0].dptr
= header_buf
;
5352 data
[1].dsize
= value
.dsize
;
5353 data
[1].dptr
= value
.dptr
;
5355 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5357 fprintf(stderr
, "Failed to write record %s to file %s\n",
5366 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5367 int argc
, const char **argv
)
5369 const char *db_name
;
5370 struct ctdb_db_context
*db
;
5371 struct ctdb_record_handle
*h
;
5374 bool readonly
= false;
5377 if (argc
< 2 || argc
> 3) {
5382 if (strcmp(argv
[2], "readonly") == 0) {
5389 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5393 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
5394 fprintf(stderr
, "DB %s is not a volatile database\n",
5399 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5402 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5406 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5408 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5412 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5413 db
, key
, readonly
, &h
, NULL
, &data
);
5415 fprintf(stderr
, "Failed to read record for key %s\n",
5418 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5419 (int)data
.dsize
, data
.dptr
);
5426 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5427 int argc
, const char **argv
)
5429 const char *db_name
;
5430 struct ctdb_db_context
*db
;
5431 struct ctdb_record_handle
*h
;
5440 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5444 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
5445 fprintf(stderr
, "DB %s is not a volatile database\n",
5450 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5453 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5457 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5459 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5463 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5465 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5469 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5470 db
, key
, false, &h
, NULL
, NULL
);
5472 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5476 ret
= ctdb_store_record(h
, data
);
5478 fprintf(stderr
, "Failed to store record for key %s\n",
5486 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5487 int argc
, const char **argv
)
5489 const char *db_name
;
5490 struct ctdb_db_context
*db
;
5491 struct ctdb_record_handle
*h
;
5500 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5504 if (db_flags
& CTDB_DB_FLAGS_PERSISTENT
) {
5505 fprintf(stderr
, "DB %s is not a volatile database\n",
5510 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5513 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5517 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5519 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5523 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5524 db
, key
, false, &h
, NULL
, &data
);
5526 fprintf(stderr
, "Failed to fetch record for key %s\n",
5531 ret
= ctdb_delete_record(h
);
5533 fprintf(stderr
, "Failed to delete record for key %s\n",
5541 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5542 int argc
, const char **argv
)
5544 struct sockaddr_in sin
;
5550 usage("chktcpport");
5553 port
= atoi(argv
[0]);
5555 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5557 fprintf(stderr
, "Failed to open local socket\n");
5561 v
= fcntl(s
, F_GETFL
, 0);
5562 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5563 fprintf(stderr
, "Unable to set socket non-blocking\n");
5568 bzero(&sin
, sizeof(sin
));
5569 sin
.sin_family
= AF_INET
;
5570 sin
.sin_port
= htons(port
);
5571 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5574 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5581 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5582 int argc
, const char **argv
)
5585 const char *db_name
;
5590 usage("getdbseqnum");
5593 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5597 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5598 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5601 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5606 printf("0x%"PRIx64
"\n", seqnum
);
5610 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5611 int argc
, const char **argv
)
5613 const char *nodestring
= NULL
;
5614 struct ctdb_node_map
*nodemap
;
5616 bool print_hdr
= false;
5619 usage("nodestatus");
5623 nodestring
= argv
[0];
5624 if (strcmp(nodestring
, "all") == 0) {
5629 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5633 if (options
.machinereadable
) {
5634 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5636 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5640 for (i
=0; i
<nodemap
->num
; i
++) {
5641 ret
|= nodemap
->node
[i
].flags
;
5650 } db_stats_fields
[] = {
5651 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5652 DBSTATISTICS_FIELD(db_ro_delegations
),
5653 DBSTATISTICS_FIELD(db_ro_revokes
),
5654 DBSTATISTICS_FIELD(locks
.num_calls
),
5655 DBSTATISTICS_FIELD(locks
.num_current
),
5656 DBSTATISTICS_FIELD(locks
.num_pending
),
5657 DBSTATISTICS_FIELD(locks
.num_failed
),
5658 DBSTATISTICS_FIELD(db_ro_delegations
),
5661 static void print_dbstatistics(const char *db_name
,
5662 struct ctdb_db_statistics
*s
)
5665 const char *prefix
= NULL
;
5668 printf("DB Statistics %s\n", db_name
);
5670 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5671 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5672 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5674 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5675 prefix
= db_stats_fields
[i
].name
;
5676 printf(" %*.*s\n", preflen
-1, preflen
-1,
5677 db_stats_fields
[i
].name
);
5682 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5683 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5684 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5687 printf(" hop_count_buckets:");
5688 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5689 printf(" %d", s
->hop_count_bucket
[i
]);
5693 printf(" lock_buckets:");
5694 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5695 printf(" %d", s
->locks
.buckets
[i
]);
5699 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5700 "locks_latency MIN/AVG/MAX",
5701 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5702 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5704 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5705 "vacuum_latency MIN/AVG/MAX",
5706 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5707 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5709 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5710 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5712 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5713 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5714 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5720 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5721 int argc
, const char **argv
)
5724 const char *db_name
;
5725 struct ctdb_db_statistics
*dbstats
;
5729 usage("dbstatistics");
5732 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5736 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5737 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5740 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5745 print_dbstatistics(db_name
, dbstats
);
5749 struct disable_takeover_runs_state
{
5757 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5760 struct disable_takeover_runs_state
*state
=
5761 (struct disable_takeover_runs_state
*)private_data
;
5764 if (data
.dsize
!= sizeof(int)) {
5769 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5770 ret
= *(int *)data
.dptr
;
5772 state
->status
= ret
;
5776 for (i
=0; i
<state
->node_count
; i
++) {
5777 if (state
->pnn_list
[i
] == ret
) {
5778 state
->reply
[i
] = true;
5784 for (i
=0; i
<state
->node_count
; i
++) {
5785 if (! state
->reply
[i
]) {
5786 state
->done
= false;
5792 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5793 struct ctdb_context
*ctdb
, uint32_t timeout
,
5794 uint32_t *pnn_list
, int count
)
5796 struct ctdb_disable_message disable
= { 0 };
5797 struct disable_takeover_runs_state state
;
5800 disable
.pnn
= ctdb
->pnn
;
5801 disable
.srvid
= next_srvid(ctdb
);
5802 disable
.timeout
= timeout
;
5804 state
.pnn_list
= pnn_list
;
5805 state
.node_count
= count
;
5808 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5809 if (state
.reply
== NULL
) {
5813 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5815 disable_takeover_run_handler
,
5821 for (i
=0; i
<count
; i
++) {
5822 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5831 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5833 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5835 ret
= (state
.status
>= 0 ? 0 : 1);
5839 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5840 disable
.srvid
, &state
);
5844 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5845 int argc
, const char **argv
)
5847 const char *nodestring
= NULL
;
5848 struct ctdb_node_map
*nodemap
, *nodemap2
;
5849 struct ctdb_req_control request
;
5850 uint32_t *pnn_list
, *pnn_list2
;
5851 int ret
, count
, count2
;
5858 nodestring
= argv
[0];
5861 nodemap
= get_nodemap(ctdb
, false);
5862 if (nodemap
== NULL
) {
5866 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5870 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5871 mem_ctx
, &pnn_list
);
5873 fprintf(stderr
, "Memory allocation error\n");
5877 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5878 mem_ctx
, &pnn_list2
);
5880 fprintf(stderr
, "Memory allocation error\n");
5884 /* Disable takeover runs on all connected nodes. A reply
5885 * indicating success is needed from each node so all nodes
5886 * will need to be active.
5888 * A check could be added to not allow reloading of IPs when
5889 * there are disconnected nodes. However, this should
5890 * probably be left up to the administrator.
5892 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5895 fprintf(stderr
, "Failed to disable takeover runs\n");
5899 /* Now tell all the desired nodes to reload their public IPs.
5900 * Keep trying this until it succeeds. This assumes all
5901 * failures are transient, which might not be true...
5903 ctdb_req_control_reload_public_ips(&request
);
5904 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5905 pnn_list2
, count2
, TIMEOUT(),
5906 &request
, NULL
, NULL
);
5908 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5911 /* It isn't strictly necessary to wait until takeover runs are
5912 * re-enabled but doing so can't hurt.
5914 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5916 fprintf(stderr
, "Failed to enable takeover runs\n");
5920 return ipreallocate(mem_ctx
, ctdb
);
5923 static int control_ipiface(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5924 int argc
, const char **argv
)
5926 ctdb_sock_addr addr
;
5933 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
5934 fprintf(stderr
, "Failed to Parse IP %s\n", argv
[0]);
5938 iface
= ctdb_sys_find_ifname(&addr
);
5939 if (iface
== NULL
) {
5940 fprintf(stderr
, "Failed to find interface for IP %s\n",
5950 static const struct ctdb_cmd
{
5952 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5953 bool without_daemon
; /* can be run without daemon running ? */
5954 bool remote
; /* can be run on remote nodes */
5957 } ctdb_commands
[] = {
5958 { "version", control_version
, true, false,
5959 "show version of ctdb", NULL
},
5960 { "status", control_status
, false, true,
5961 "show node status", NULL
},
5962 { "uptime", control_uptime
, false, true,
5963 "show node uptime", NULL
},
5964 { "ping", control_ping
, false, true,
5965 "ping all nodes", NULL
},
5966 { "runstate", control_runstate
, false, true,
5967 "get/check runstate of a node",
5968 "[setup|first_recovery|startup|running]" },
5969 { "getvar", control_getvar
, false, true,
5970 "get a tunable variable", "<name>" },
5971 { "setvar", control_setvar
, false, true,
5972 "set a tunable variable", "<name> <value>" },
5973 { "listvars", control_listvars
, false, true,
5974 "list tunable variables", NULL
},
5975 { "statistics", control_statistics
, false, true,
5976 "show ctdb statistics", NULL
},
5977 { "statisticsreset", control_statistics_reset
, false, true,
5978 "reset ctdb statistics", NULL
},
5979 { "stats", control_stats
, false, true,
5980 "show rolling statistics", "[count]" },
5981 { "ip", control_ip
, false, true,
5982 "show public ips", "[all]" },
5983 { "ipinfo", control_ipinfo
, false, true,
5984 "show public ip details", "<ip>" },
5985 { "ifaces", control_ifaces
, false, true,
5986 "show interfaces", NULL
},
5987 { "setifacelink", control_setifacelink
, false, true,
5988 "set interface link status", "<iface> up|down" },
5989 { "process-exists", control_process_exists
, false, true,
5990 "check if a process exists on a node", "<pid>" },
5991 { "getdbmap", control_getdbmap
, false, true,
5992 "show attached databases", NULL
},
5993 { "getdbstatus", control_getdbstatus
, false, true,
5994 "show database status", "<dbname|dbid>" },
5995 { "catdb", control_catdb
, false, false,
5996 "dump cluster-wide ctdb database", "<dbname|dbid>" },
5997 { "cattdb", control_cattdb
, false, false,
5998 "dump local ctdb database", "<dbname|dbid>" },
5999 { "getmonmode", control_getmonmode
, false, true,
6000 "show monitoring mode", NULL
},
6001 { "getcapabilities", control_getcapabilities
, false, true,
6002 "show node capabilities", NULL
},
6003 { "pnn", control_pnn
, false, false,
6004 "show the pnn of the currnet node", NULL
},
6005 { "lvs", control_lvs
, false, false,
6006 "show lvs configuration", "master|list|status" },
6007 { "disablemonitor", control_disable_monitor
, false, true,
6008 "disable monitoring", NULL
},
6009 { "enablemonitor", control_enable_monitor
, false, true,
6010 "enable monitoring", NULL
},
6011 { "setdebug", control_setdebug
, false, true,
6012 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6013 { "getdebug", control_getdebug
, false, true,
6014 "get debug level", NULL
},
6015 { "attach", control_attach
, false, false,
6016 "attach a database", "<dbname> [persistent]" },
6017 { "detach", control_detach
, false, false,
6018 "detach database(s)", "<dbname|dbid> ..." },
6019 { "dumpmemory", control_dumpmemory
, false, true,
6020 "dump ctdbd memory map", NULL
},
6021 { "rddumpmemory", control_rddumpmemory
, false, true,
6022 "dump recoverd memory map", NULL
},
6023 { "getpid", control_getpid
, false, true,
6024 "get ctdbd process ID", NULL
},
6025 { "disable", control_disable
, false, true,
6026 "disable a node", NULL
},
6027 { "enable", control_enable
, false, true,
6028 "enable a node", NULL
},
6029 { "stop", control_stop
, false, true,
6030 "stop a node", NULL
},
6031 { "continue", control_continue
, false, true,
6032 "continue a stopped node", NULL
},
6033 { "ban", control_ban
, false, true,
6034 "ban a node", "<bantime>"},
6035 { "unban", control_unban
, false, true,
6036 "unban a node", NULL
},
6037 { "shutdown", control_shutdown
, false, true,
6038 "shutdown ctdb daemon", NULL
},
6039 { "recover", control_recover
, false, true,
6040 "force recovery", NULL
},
6041 { "sync", control_ipreallocate
, false, true,
6042 "run ip reallocation (deprecated)", NULL
},
6043 { "ipreallocate", control_ipreallocate
, false, true,
6044 "run ip reallocation", NULL
},
6045 { "isnotrecmaster", control_isnotrecmaster
, false, false,
6046 "check if local node is the recmaster", NULL
},
6047 { "gratarp", control_gratarp
, false, true,
6048 "send a gratuitous arp", "<ip> <interface>" },
6049 { "tickle", control_tickle
, true, false,
6050 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6051 { "gettickles", control_gettickles
, false, true,
6052 "get the list of tickles", "<ip> [<port>]" },
6053 { "addtickle", control_addtickle
, false, true,
6054 "add a tickle", "<ip>:<port> <ip>:<port>" },
6055 { "deltickle", control_deltickle
, false, true,
6056 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6057 { "check_srvids", control_check_srvids
, false, true,
6058 "check if srvid is registered", "<id> [<id> ...]" },
6059 { "listnodes", control_listnodes
, true, true,
6060 "list nodes in the cluster", NULL
},
6061 { "reloadnodes", control_reloadnodes
, false, false,
6062 "reload the nodes file all nodes", NULL
},
6063 { "moveip", control_moveip
, false, false,
6064 "move an ip address to another node", "<ip> <node>" },
6065 { "addip", control_addip
, false, true,
6066 "add an ip address to a node", "<ip/mask> <iface>" },
6067 { "delip", control_delip
, false, true,
6068 "delete an ip address from a node", "<ip>" },
6069 { "backupdb", control_backupdb
, false, false,
6070 "backup a database into a file", "<dbname|dbid> <file>" },
6071 { "restoredb", control_restoredb
, false, false,
6072 "restore a database from a file", "<file> [dbname]" },
6073 { "dumpdbbackup", control_dumpdbbackup
, true, false,
6074 "dump database from a backup file", "<file>" },
6075 { "wipedb", control_wipedb
, false, false,
6076 "wipe the contents of a database.", "<dbname|dbid>"},
6077 { "recmaster", control_recmaster
, false, true,
6078 "show the pnn for the recovery master", NULL
},
6079 { "event", control_event
, true, false,
6080 "event and event script commands", NULL
},
6081 { "scriptstatus", control_scriptstatus
, true, false,
6082 "show event script status",
6083 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6084 { "natgw", control_natgw
, false, false,
6085 "show natgw configuration", "master|list|status" },
6086 { "natgwlist", control_natgwlist
, false, false,
6087 "show the nodes belonging to this natgw configuration", NULL
},
6088 { "getreclock", control_getreclock
, false, true,
6089 "get recovery lock file", NULL
},
6090 { "setlmasterrole", control_setlmasterrole
, false, true,
6091 "set LMASTER role", "on|off" },
6092 { "setrecmasterrole", control_setrecmasterrole
, false, true,
6093 "set RECMASTER role", "on|off"},
6094 { "setdbreadonly", control_setdbreadonly
, false, true,
6095 "enable readonly records", "<dbname|dbid>" },
6096 { "setdbsticky", control_setdbsticky
, false, true,
6097 "enable sticky records", "<dbname|dbid>"},
6098 { "pfetch", control_pfetch
, false, false,
6099 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6100 { "pstore", control_pstore
, false, false,
6101 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6102 { "pdelete", control_pdelete
, false, false,
6103 "delete record from persistent database", "<dbname|dbid> <key>" },
6104 { "ptrans", control_ptrans
, false, false,
6105 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6106 { "tfetch", control_tfetch
, false, true,
6107 "fetch a record", "<tdb-file> <key> [<file>]" },
6108 { "tstore", control_tstore
, false, true,
6109 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6110 { "readkey", control_readkey
, false, false,
6111 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6112 { "writekey", control_writekey
, false, false,
6113 "write value for a database key", "<dbname|dbid> <key> <value>" },
6114 { "deletekey", control_deletekey
, false, false,
6115 "delete a database key", "<dbname|dbid> <key>" },
6116 { "checktcpport", control_checktcpport
, true, false,
6117 "check if a service is bound to a specific tcp port or not", "<port>" },
6118 { "getdbseqnum", control_getdbseqnum
, false, false,
6119 "get database sequence number", "<dbname|dbid>" },
6120 { "nodestatus", control_nodestatus
, false, true,
6121 "show and return node status", "[all|<pnn-list>]" },
6122 { "dbstatistics", control_dbstatistics
, false, true,
6123 "show database statistics", "<dbname|dbid>" },
6124 { "reloadips", control_reloadips
, false, false,
6125 "reload the public addresses file", "[all|<pnn-list>]" },
6126 { "ipiface", control_ipiface
, true, false,
6127 "Find the interface an ip address is hosted on", "<ip>" },
6130 static const struct ctdb_cmd
*match_command(const char *command
)
6132 const struct ctdb_cmd
*cmd
;
6135 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6136 cmd
= &ctdb_commands
[i
];
6137 if (strlen(command
) == strlen(cmd
->name
) &&
6138 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6148 * Show usage message
6150 static void usage_full(void)
6154 poptPrintHelp(pc
, stdout
, 0);
6155 printf("\nCommands:\n");
6156 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6157 printf(" %-15s %-27s %s\n",
6158 ctdb_commands
[i
].name
,
6159 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6160 ctdb_commands
[i
].msg
);
6164 static void usage(const char *command
)
6166 const struct ctdb_cmd
*cmd
;
6168 if (command
== NULL
) {
6173 cmd
= match_command(command
);
6177 poptPrintUsage(pc
, stdout
, 0);
6178 printf("\nCommands:\n");
6179 printf(" %-15s %-27s %s\n",
6180 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6186 struct poptOption cmdline_options
[] = {
6188 { "socket", 's', POPT_ARG_STRING
, &options
.socket
, 0,
6189 "CTDB socket path", "filename" },
6190 { "debug", 'd', POPT_ARG_STRING
, &options
.debuglevelstr
, 0,
6192 { "timelimit", 't', POPT_ARG_INT
, &options
.timelimit
, 0,
6193 "timelimit (in seconds)" },
6194 { "node", 'n', POPT_ARG_INT
, &options
.pnn
, 0,
6195 "node specification - integer" },
6196 { NULL
, 'Y', POPT_ARG_NONE
, &options
.machinereadable
, 0,
6197 "enable machine readable output", NULL
},
6198 { "separator", 'x', POPT_ARG_STRING
, &options
.sep
, 0,
6199 "specify separator for machine readable output", "CHAR" },
6200 { NULL
, 'X', POPT_ARG_NONE
, &options
.machineparsable
, 0,
6201 "enable machine parsable output with separator |", NULL
},
6202 { "verbose", 'v', POPT_ARG_NONE
, &options
.verbose
, 0,
6203 "enable verbose output", NULL
},
6204 { "maxruntime", 'T', POPT_ARG_INT
, &options
.maxruntime
, 0,
6205 "die if runtime exceeds this limit (in seconds)" },
6209 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6212 TALLOC_CTX
*tmp_ctx
;
6213 struct ctdb_context
*ctdb
;
6216 uint64_t srvid_offset
;
6218 tmp_ctx
= talloc_new(NULL
);
6219 if (tmp_ctx
== NULL
) {
6220 fprintf(stderr
, "Memory allocation error\n");
6224 if (cmd
->without_daemon
) {
6225 if (options
.pnn
!= -1) {
6227 "Cannot specify node for command %s\n",
6232 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6233 talloc_free(tmp_ctx
);
6237 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6239 fprintf(stderr
, "Memory allocation error\n");
6243 ctdb
->ev
= tevent_context_init(ctdb
);
6244 if (ctdb
->ev
== NULL
) {
6245 fprintf(stderr
, "Failed to initialize tevent\n");
6249 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, options
.socket
, &ctdb
->client
);
6251 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6254 if (!find_node_xpnn(ctdb
, NULL
)) {
6255 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6260 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6261 srvid_offset
= getpid() & 0xFFFF;
6262 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6264 if (options
.pnn
!= -1) {
6265 status
= verify_pnn(ctdb
, options
.pnn
);
6270 ctdb
->cmd_pnn
= options
.pnn
;
6272 ctdb
->cmd_pnn
= ctdb
->pnn
;
6275 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6276 fprintf(stderr
, "Node cannot be specified for command %s\n",
6281 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6282 talloc_free(tmp_ctx
);
6286 talloc_free(tmp_ctx
);
6290 static void signal_handler(int sig
)
6292 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6295 static void alarm_handler(int sig
)
6297 /* Kill any child processes */
6298 signal(SIGTERM
, signal_handler
);
6304 int main(int argc
, const char *argv
[])
6307 const char **extra_argv
;
6309 const struct ctdb_cmd
*cmd
;
6310 const char *ctdb_socket
;
6316 /* Set default options */
6317 options
.socket
= CTDB_SOCKET
;
6318 options
.debuglevelstr
= NULL
;
6319 options
.timelimit
= 10;
6321 options
.maxruntime
= 0;
6324 ctdb_socket
= getenv("CTDB_SOCKET");
6325 if (ctdb_socket
!= NULL
) {
6326 options
.socket
= ctdb_socket
;
6329 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6330 POPT_CONTEXT_KEEP_FIRST
);
6331 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6332 fprintf(stderr
, "Invalid option %s: %s\n",
6333 poptBadOption(pc
, 0), poptStrerror(opt
));
6337 if (options
.maxruntime
== 0) {
6338 const char *ctdb_timeout
;
6340 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6341 if (ctdb_timeout
!= NULL
) {
6342 options
.maxruntime
= strtoul(ctdb_timeout
, NULL
, 0);
6344 options
.maxruntime
= 120;
6347 if (options
.maxruntime
<= 120) {
6348 /* default timeout is 120 seconds */
6349 options
.maxruntime
= 120;
6352 if (options
.machineparsable
) {
6353 options
.machinereadable
= 1;
6356 /* setup the remaining options for the commands */
6358 extra_argv
= poptGetArgs(pc
);
6361 while (extra_argv
[extra_argc
]) extra_argc
++;
6364 if (extra_argc
< 1) {
6368 cmd
= match_command(extra_argv
[0]);
6370 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6374 /* Enable logging */
6375 setup_logging("ctdb", DEBUG_STDERR
);
6376 if (debug_level_parse(options
.debuglevelstr
, &loglevel
)) {
6377 DEBUGLEVEL
= loglevel
;
6379 DEBUGLEVEL
= DEBUG_ERR
;
6382 signal(SIGALRM
, alarm_handler
);
6383 alarm(options
.maxruntime
);
6385 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6390 (void)poptFreeContext(pc
);