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"
44 #include "client/client_sync.h"
46 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
48 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
49 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
53 const char *debuglevelstr
;
61 int printemptyrecords
;
68 static poptContext pc
;
71 struct tevent_context
*ev
;
72 struct ctdb_client_context
*client
;
73 struct ctdb_node_map
*nodemap
;
74 uint32_t pnn
, cmd_pnn
;
78 static void usage(const char *command
);
84 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
86 return (tv2
->tv_sec
- tv
->tv_sec
) +
87 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
90 static struct ctdb_node_and_flags
*get_node_by_pnn(
91 struct ctdb_node_map
*nodemap
,
96 for (i
=0; i
<nodemap
->num
; i
++) {
97 if (nodemap
->node
[i
].pnn
== pnn
) {
98 return &nodemap
->node
[i
];
104 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
106 static const struct {
110 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
111 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
112 { NODE_FLAGS_BANNED
, "BANNED" },
113 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
114 { NODE_FLAGS_DELETED
, "DELETED" },
115 { NODE_FLAGS_STOPPED
, "STOPPED" },
116 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
118 char *flags_str
= NULL
;
121 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
122 if (flags
& flag_names
[i
].flag
) {
123 if (flags_str
== NULL
) {
124 flags_str
= talloc_asprintf(mem_ctx
,
125 "%s", flag_names
[i
].name
);
127 flags_str
= talloc_asprintf_append(flags_str
,
128 "|%s", flag_names
[i
].name
);
130 if (flags_str
== NULL
) {
131 return "OUT-OF-MEMORY";
135 if (flags_str
== NULL
) {
142 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
149 * Get consistent nodemap information.
151 * If nodemap is already cached, use that. If not get it.
152 * If the current node is BANNED, then get nodemap from "better" node.
154 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
157 struct ctdb_node_map
*nodemap
;
158 struct ctdb_node_and_flags
*node
;
159 uint32_t current_node
;
163 TALLOC_FREE(ctdb
->nodemap
);
166 if (ctdb
->nodemap
!= NULL
) {
167 return ctdb
->nodemap
;
170 tmp_ctx
= talloc_new(ctdb
);
171 if (tmp_ctx
== NULL
) {
175 current_node
= ctdb
->pnn
;
177 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
178 current_node
, TIMEOUT(), &nodemap
);
180 fprintf(stderr
, "Failed to get nodemap from node %u\n",
185 node
= get_node_by_pnn(nodemap
, current_node
);
186 if (node
->flags
& NODE_FLAGS_BANNED
) {
189 current_node
= (current_node
+ 1) % nodemap
->num
;
190 node
= get_node_by_pnn(nodemap
, current_node
);
192 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
195 } while (current_node
!= ctdb
->pnn
);
197 if (current_node
== ctdb
->pnn
) {
198 /* Tried all nodes in the cluster */
199 fprintf(stderr
, "Warning: All nodes are banned.\n");
206 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
210 talloc_free(tmp_ctx
);
214 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
216 struct ctdb_node_map
*nodemap
;
224 nodemap
= get_nodemap(ctdb
, false);
225 if (nodemap
== NULL
) {
230 for (i
=0; i
<nodemap
->num
; i
++) {
231 if (nodemap
->node
[i
].pnn
== pnn
) {
237 fprintf(stderr
, "Node %u does not exist\n", pnn
);
241 if (nodemap
->node
[i
].flags
&
242 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
243 fprintf(stderr
, "Node %u has status %s\n", pnn
,
244 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
251 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
252 struct ctdb_node_map
*nodemap
)
254 struct ctdb_node_map
*nodemap2
;
256 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
257 if (nodemap2
== NULL
) {
261 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
263 if (nodemap2
->node
== NULL
) {
264 talloc_free(nodemap2
);
272 * Get the number and the list of matching nodes
274 * nodestring := NULL | all | pnn,[pnn,...]
276 * If nodestring is NULL, use the current node.
278 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
279 const char *nodestring
,
280 struct ctdb_node_map
**out
)
282 struct ctdb_node_map
*nodemap
, *nodemap2
;
283 struct ctdb_node_and_flags
*node
;
286 nodemap
= get_nodemap(ctdb
, false);
287 if (nodemap
== NULL
) {
291 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
292 if (nodemap2
== NULL
) {
296 if (nodestring
== NULL
) {
297 for (i
=0; i
<nodemap
->num
; i
++) {
298 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
299 nodemap2
->node
[0] = nodemap
->node
[i
];
308 if (strcmp(nodestring
, "all") == 0) {
309 for (i
=0; i
<nodemap
->num
; i
++) {
310 nodemap2
->node
[i
] = nodemap
->node
[i
];
312 nodemap2
->num
= nodemap
->num
;
318 ns
= talloc_strdup(mem_ctx
, nodestring
);
323 tok
= strtok(ns
, ",");
324 while (tok
!= NULL
) {
328 pnn
= (uint32_t)strtoul(tok
, &endptr
, 0);
329 if (pnn
== 0 && tok
== endptr
) {
330 fprintf(stderr
, "Invalid node %s\n", tok
);
334 node
= get_node_by_pnn(nodemap
, pnn
);
336 fprintf(stderr
, "Node %u does not exist\n",
341 nodemap2
->node
[nodemap2
->num
] = *node
;
344 tok
= strtok(NULL
, ",");
353 /* Compare IP address */
354 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
358 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
362 switch (ip1
->sa
.sa_family
) {
364 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
365 sizeof(struct in_addr
)) == 0);
369 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
370 sizeof(struct in6_addr
)) == 0);
377 /* Append a node to a node map with given address and flags */
378 static bool node_map_add(struct ctdb_node_map
*nodemap
,
379 const char *nstr
, uint32_t flags
)
383 struct ctdb_node_and_flags
*n
;
385 if (! parse_ip(nstr
, NULL
, 0, &addr
)) {
386 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
391 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
392 struct ctdb_node_and_flags
, num
+1);
393 if (nodemap
->node
== NULL
) {
397 n
= &nodemap
->node
[num
];
402 nodemap
->num
= num
+1;
406 /* Read a nodes file into a node map */
407 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
413 struct ctdb_node_map
*nodemap
;
415 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
416 if (nodemap
== NULL
) {
420 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
425 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
429 for (i
=0; i
<nlines
; i
++) {
435 /* strip leading spaces */
436 while((*node
== ' ') || (*node
== '\t')) {
442 /* strip trailing spaces */
444 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
454 /* A "deleted" node is a node that is
455 commented out in the nodes file. This is
456 used instead of removing a line, which
457 would cause subsequent nodes to change
459 flags
= NODE_FLAGS_DELETED
;
460 node
= discard_const("0.0.0.0");
464 if (! node_map_add(nodemap
, node
, flags
)) {
466 TALLOC_FREE(nodemap
);
475 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
477 struct ctdb_node_map
*nodemap
;
479 const char *nodes_list
= NULL
;
481 if (pnn
!= CTDB_UNKNOWN_PNN
) {
482 nodepath
= talloc_asprintf(mem_ctx
, "CTDB_NODES_%u", pnn
);
483 if (nodepath
!= NULL
) {
484 nodes_list
= getenv(nodepath
);
487 if (nodes_list
== NULL
) {
488 nodes_list
= getenv("CTDB_NODES");
490 if (nodes_list
== NULL
) {
491 const char *basedir
= getenv("CTDB_BASE");
492 if (basedir
== NULL
) {
493 basedir
= CTDB_ETCDIR
;
495 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
496 if (nodes_list
== NULL
) {
497 fprintf(stderr
, "Memory allocation error\n");
502 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
503 if (nodemap
== NULL
) {
504 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
512 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
513 struct ctdb_context
*ctdb
,
514 struct ctdb_dbid_map
*dbmap
,
517 struct ctdb_dbid
*db
= NULL
;
521 for (i
=0; i
<dbmap
->num
; i
++) {
522 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
523 ctdb
->pnn
, TIMEOUT(),
524 dbmap
->dbs
[i
].db_id
, &name
);
529 if (strcmp(db_name
, name
) == 0) {
530 talloc_free(discard_const(name
));
539 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
540 const char *db_arg
, uint32_t *db_id
,
541 const char **db_name
, uint8_t *db_flags
)
543 struct ctdb_dbid_map
*dbmap
;
544 struct ctdb_dbid
*db
= NULL
;
546 const char *name
= NULL
;
549 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
550 ctdb
->pnn
, TIMEOUT(), &dbmap
);
555 if (strncmp(db_arg
, "0x", 2) == 0) {
556 id
= strtoul(db_arg
, NULL
, 0);
557 for (i
=0; i
<dbmap
->num
; i
++) {
558 if (id
== dbmap
->dbs
[i
].db_id
) {
565 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
569 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
574 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
575 ctdb
->pnn
, TIMEOUT(), id
, &name
);
584 if (db_name
!= NULL
) {
585 *db_name
= talloc_strdup(mem_ctx
, name
);
587 if (db_flags
!= NULL
) {
588 *db_flags
= db
->flags
;
593 static int h2i(char h
)
595 if (h
>= 'a' && h
<= 'f') {
598 if (h
>= 'A' && h
<= 'F') {
604 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
611 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
616 data
.dsize
= len
/ 2;
617 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
618 if (data
.dptr
== NULL
) {
622 for (i
=0; i
<data
.dsize
; i
++) {
623 data
.dptr
[i
] = h2i(str
[i
*2]) << 4 | h2i(str
[i
*2+1]);
630 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
636 if (strncmp(str
, "0x", 2) == 0) {
637 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
639 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
640 if (data
.dptr
== NULL
) {
650 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
651 const char *path
, int argc
, const char **argv
)
654 int save_errno
, status
, ret
;
655 const char **new_argv
;
658 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
659 if (new_argv
== NULL
) {
664 for (i
=0; i
<argc
; i
++) {
665 new_argv
[i
+1] = argv
[i
];
667 new_argv
[argc
+1] = NULL
;
672 talloc_free(new_argv
);
673 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
674 command
, path
, strerror(save_errno
));
679 ret
= execv(path
, discard_const(new_argv
));
683 /* Should not happen */
687 talloc_free(new_argv
);
689 ret
= waitpid(pid
, &status
, 0);
692 fprintf(stderr
, "waitpid() failed for %s - %s\n",
693 command
, strerror(save_errno
));
697 if (WIFEXITED(status
)) {
698 int pstatus
= WEXITSTATUS(status
);
699 if (WIFSIGNALED(status
)) {
700 fprintf(stderr
, "%s terminated with signal %d\n",
701 command
, WTERMSIG(status
));
703 } else if (pstatus
>= 64 && pstatus
< 255) {
704 fprintf(stderr
, "%s failed with error %d\n",
705 command
, pstatus
-64);
711 } else if (WIFSIGNALED(status
)) {
712 fprintf(stderr
, "%s terminated with signal %d\n",
713 command
, WTERMSIG(status
));
724 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
725 int argc
, const char **argv
)
727 printf("%s\n", CTDB_VERSION_STRING
);
731 static bool partially_online(TALLOC_CTX
*mem_ctx
,
732 struct ctdb_context
*ctdb
,
733 struct ctdb_node_and_flags
*node
)
735 struct ctdb_iface_list
*iface_list
;
739 if (node
->flags
!= 0) {
743 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
744 node
->pnn
, TIMEOUT(), &iface_list
);
750 for (i
=0; i
< iface_list
->num
; i
++) {
751 if (iface_list
->iface
[i
].link_state
== 0) {
760 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
761 struct ctdb_context
*ctdb
,
762 struct ctdb_node_map
*nodemap
,
765 struct ctdb_node_and_flags
*node
;
768 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
772 "Disconnected", options
.sep
,
773 "Banned", options
.sep
,
774 "Disabled", options
.sep
,
775 "Unhealthy", options
.sep
,
776 "Stopped", options
.sep
,
777 "Inactive", options
.sep
,
778 "PartiallyOnline", options
.sep
,
779 "ThisNode", options
.sep
);
781 for (i
=0; i
<nodemap
->num
; i
++) {
782 node
= &nodemap
->node
[i
];
783 if (node
->flags
& NODE_FLAGS_DELETED
) {
787 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
789 node
->pnn
, options
.sep
,
790 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
),
792 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
793 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
794 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
796 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
797 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
798 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
799 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
800 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
805 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
806 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
809 struct ctdb_node_and_flags
*node
;
810 int num_deleted_nodes
= 0;
813 for (i
=0; i
<nodemap
->num
; i
++) {
814 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
820 if (num_deleted_nodes
== 0) {
821 printf("Number of nodes:%d\n", nodemap
->num
);
823 printf("Number of nodes:%d "
824 "(including %d deleted nodes)\n",
825 nodemap
->num
, num_deleted_nodes
);
829 for (i
=0; i
<nodemap
->num
; i
++) {
830 node
= &nodemap
->node
[i
];
831 if (node
->flags
& NODE_FLAGS_DELETED
) {
835 printf("pnn:%u %-16s %s%s\n",
837 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
),
838 partially_online(mem_ctx
, ctdb
, node
) ?
840 pretty_print_flags(mem_ctx
, node
->flags
),
841 node
->pnn
== mypnn
? " (THIS NODE)" : "");
845 static void print_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
846 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
847 struct ctdb_vnn_map
*vnnmap
, int recmode
,
852 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
854 if (vnnmap
->generation
== INVALID_GENERATION
) {
855 printf("Generation:INVALID\n");
857 printf("Generation:%u\n", vnnmap
->generation
);
859 printf("Size:%d\n", vnnmap
->size
);
860 for (i
=0; i
<vnnmap
->size
; i
++) {
861 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
864 printf("Recovery mode:%s (%d)\n",
865 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
867 printf("Recovery master:%d\n", recmaster
);
870 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
871 int argc
, const char **argv
)
873 struct ctdb_node_map
*nodemap
;
874 struct ctdb_vnn_map
*vnnmap
;
883 nodemap
= get_nodemap(ctdb
, false);
884 if (nodemap
== NULL
) {
888 if (options
.machinereadable
== 1) {
889 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
893 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
894 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
899 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
900 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
905 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
906 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
911 print_status(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, vnnmap
,
916 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
917 int argc
, const char **argv
)
919 struct ctdb_uptime
*uptime
;
920 int ret
, tmp
, days
, hours
, minutes
, seconds
;
922 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
923 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
928 printf("Current time of node %-4u : %s",
929 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
931 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
932 seconds
= tmp
% 60; tmp
/= 60;
933 minutes
= tmp
% 60; tmp
/= 60;
934 hours
= tmp
% 24; tmp
/= 24;
937 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
938 days
, hours
, minutes
, seconds
,
939 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
941 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
942 seconds
= tmp
% 60; tmp
/= 60;
943 minutes
= tmp
% 60; tmp
/= 60;
944 hours
= tmp
% 24; tmp
/= 24;
947 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
948 days
, hours
, minutes
, seconds
,
949 ctime(&uptime
->last_recovery_finished
.tv_sec
));
951 printf("Duration of last recovery/failover: %lf seconds\n",
952 timeval_delta(&uptime
->last_recovery_finished
,
953 &uptime
->last_recovery_started
));
958 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
959 int argc
, const char **argv
)
962 int ret
, num_clients
;
964 tv
= timeval_current();
965 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
966 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
971 printf("response from %u time=%.6f sec (%d clients)\n",
972 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
976 const char *runstate_to_string(enum ctdb_runstate runstate
);
977 enum ctdb_runstate
runstate_from_string(const char *runstate_str
);
979 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
980 int argc
, const char **argv
)
982 enum ctdb_runstate runstate
;
986 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
987 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
993 for (i
=0; i
<argc
; i
++) {
994 enum ctdb_runstate t
;
997 t
= ctdb_runstate_from_string(argv
[i
]);
998 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
999 printf("Invalid run state (%s)\n", argv
[i
]);
1003 if (t
== runstate
) {
1010 printf("CTDB not in required run state (got %s)\n",
1011 ctdb_runstate_to_string(runstate
));
1015 printf("%s\n", ctdb_runstate_to_string(runstate
));
1019 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1020 int argc
, const char **argv
)
1022 struct ctdb_var_list
*tun_var_list
;
1031 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1032 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1035 "Failed to get list of variables from node %u\n",
1041 for (i
=0; i
<tun_var_list
->count
; i
++) {
1042 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1049 printf("No such tunable %s\n", argv
[0]);
1053 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1054 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1059 printf("%-26s = %u\n", argv
[0], value
);
1063 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1064 int argc
, const char **argv
)
1066 struct ctdb_var_list
*tun_var_list
;
1067 struct ctdb_tunable tunable
;
1075 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1076 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1079 "Failed to get list of variables from node %u\n",
1085 for (i
=0; i
<tun_var_list
->count
; i
++) {
1086 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1093 printf("No such tunable %s\n", argv
[0]);
1097 tunable
.name
= argv
[0];
1098 tunable
.value
= strtoul(argv
[1], NULL
, 0);
1100 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1101 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1105 "Setting obsolete tunable variable '%s'\n",
1114 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1115 int argc
, const char **argv
)
1117 struct ctdb_var_list
*tun_var_list
;
1124 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1125 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1130 for (i
=0; i
<tun_var_list
->count
; i
++) {
1131 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1140 } stats_fields
[] = {
1141 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1142 STATISTICS_FIELD(num_clients
),
1143 STATISTICS_FIELD(frozen
),
1144 STATISTICS_FIELD(recovering
),
1145 STATISTICS_FIELD(num_recoveries
),
1146 STATISTICS_FIELD(client_packets_sent
),
1147 STATISTICS_FIELD(client_packets_recv
),
1148 STATISTICS_FIELD(node_packets_sent
),
1149 STATISTICS_FIELD(node_packets_recv
),
1150 STATISTICS_FIELD(keepalive_packets_sent
),
1151 STATISTICS_FIELD(keepalive_packets_recv
),
1152 STATISTICS_FIELD(node
.req_call
),
1153 STATISTICS_FIELD(node
.reply_call
),
1154 STATISTICS_FIELD(node
.req_dmaster
),
1155 STATISTICS_FIELD(node
.reply_dmaster
),
1156 STATISTICS_FIELD(node
.reply_error
),
1157 STATISTICS_FIELD(node
.req_message
),
1158 STATISTICS_FIELD(node
.req_control
),
1159 STATISTICS_FIELD(node
.reply_control
),
1160 STATISTICS_FIELD(client
.req_call
),
1161 STATISTICS_FIELD(client
.req_message
),
1162 STATISTICS_FIELD(client
.req_control
),
1163 STATISTICS_FIELD(timeouts
.call
),
1164 STATISTICS_FIELD(timeouts
.control
),
1165 STATISTICS_FIELD(timeouts
.traverse
),
1166 STATISTICS_FIELD(locks
.num_calls
),
1167 STATISTICS_FIELD(locks
.num_current
),
1168 STATISTICS_FIELD(locks
.num_pending
),
1169 STATISTICS_FIELD(locks
.num_failed
),
1170 STATISTICS_FIELD(total_calls
),
1171 STATISTICS_FIELD(pending_calls
),
1172 STATISTICS_FIELD(childwrite_calls
),
1173 STATISTICS_FIELD(pending_childwrite_calls
),
1174 STATISTICS_FIELD(memory_used
),
1175 STATISTICS_FIELD(max_hop_count
),
1176 STATISTICS_FIELD(total_ro_delegations
),
1177 STATISTICS_FIELD(total_ro_revokes
),
1180 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1182 static void print_statistics_machine(struct ctdb_statistics
*s
,
1188 printf("CTDB version%s", options
.sep
);
1189 printf("Current time of statistics%s", options
.sep
);
1190 printf("Statistics collected since%s", options
.sep
);
1191 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1192 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1194 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1195 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1196 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1197 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1199 printf("num_reclock_recd_latency%s", options
.sep
);
1200 printf("min_reclock_recd_latency%s", options
.sep
);
1201 printf("avg_reclock_recd_latency%s", options
.sep
);
1202 printf("max_reclock_recd_latency%s", options
.sep
);
1204 printf("num_call_latency%s", options
.sep
);
1205 printf("min_call_latency%s", options
.sep
);
1206 printf("avg_call_latency%s", options
.sep
);
1207 printf("max_call_latency%s", options
.sep
);
1209 printf("num_lockwait_latency%s", options
.sep
);
1210 printf("min_lockwait_latency%s", options
.sep
);
1211 printf("avg_lockwait_latency%s", options
.sep
);
1212 printf("max_lockwait_latency%s", options
.sep
);
1214 printf("num_childwrite_latency%s", options
.sep
);
1215 printf("min_childwrite_latency%s", options
.sep
);
1216 printf("avg_childwrite_latency%s", options
.sep
);
1217 printf("max_childwrite_latency%s", options
.sep
);
1221 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1222 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1223 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1224 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1226 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1229 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1230 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1231 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1232 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1234 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1235 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1236 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1237 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1239 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1240 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1241 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1242 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1244 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1245 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1246 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1247 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1251 static void print_statistics(struct ctdb_statistics
*s
)
1253 int tmp
, days
, hours
, minutes
, seconds
;
1255 const char *prefix
= NULL
;
1258 tmp
= s
->statistics_current_time
.tv_sec
-
1259 s
->statistics_start_time
.tv_sec
;
1260 seconds
= tmp
% 60; tmp
/= 60;
1261 minutes
= tmp
% 60; tmp
/= 60;
1262 hours
= tmp
% 24; tmp
/= 24;
1265 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1266 printf("Current time of statistics : %s",
1267 ctime(&s
->statistics_current_time
.tv_sec
));
1268 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1269 days
, hours
, minutes
, seconds
,
1270 ctime(&s
->statistics_start_time
.tv_sec
));
1272 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1273 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1274 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1276 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1277 prefix
= stats_fields
[i
].name
;
1278 printf(" %*.*s\n", preflen
-1, preflen
-1,
1279 stats_fields
[i
].name
);
1284 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1285 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1286 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1289 printf(" hop_count_buckets:");
1290 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1291 printf(" %d", s
->hop_count_bucket
[i
]);
1294 printf(" lock_buckets:");
1295 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1296 printf(" %d", s
->locks
.buckets
[i
]);
1299 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1300 "locks_latency MIN/AVG/MAX",
1301 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1302 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1304 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1305 "reclock_ctdbd MIN/AVG/MAX",
1306 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1307 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1309 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1310 "reclock_recd MIN/AVG/MAX",
1311 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1312 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1314 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1315 "call_latency MIN/AVG/MAX",
1316 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1317 s
->call_latency
.max
, s
->call_latency
.num
);
1319 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1320 "childwrite_latency MIN/AVG/MAX",
1321 s
->childwrite_latency
.min
,
1322 LATENCY_AVG(s
->childwrite_latency
),
1323 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1326 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1327 int argc
, const char **argv
)
1329 struct ctdb_statistics
*stats
;
1333 usage("statistics");
1336 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1337 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1342 if (options
.machinereadable
) {
1343 print_statistics_machine(stats
, true);
1345 print_statistics(stats
);
1351 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1352 struct ctdb_context
*ctdb
,
1353 int argc
, const char **argv
)
1358 usage("statisticsreset");
1361 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1362 ctdb
->cmd_pnn
, TIMEOUT());
1370 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1371 int argc
, const char **argv
)
1373 struct ctdb_statistics_list
*slist
;
1374 int ret
, count
= 0, i
;
1375 bool show_header
= true;
1382 count
= atoi(argv
[0]);
1385 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1386 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1391 for (i
=0; i
<slist
->num
; i
++) {
1392 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1395 if (options
.machinereadable
== 1) {
1396 print_statistics_machine(&slist
->stats
[i
],
1398 show_header
= false;
1400 print_statistics(&slist
->stats
[i
]);
1402 if (count
> 0 && i
== count
) {
1410 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1412 const struct ctdb_public_ip
*ip_a
= a
;
1413 const struct ctdb_public_ip
*ip_b
= b
;
1415 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1418 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1419 struct ctdb_public_ip_list
*ips
,
1420 struct ctdb_public_ip_info
**ipinfo
,
1424 char *conf
, *avail
, *active
;
1426 if (options
.machinereadable
== 1) {
1427 printf("%s%s%s%s%s", options
.sep
,
1428 "Public IP", options
.sep
,
1429 "Node", options
.sep
);
1430 if (options
.verbose
== 1) {
1431 printf("%s%s%s%s%s%s\n",
1432 "ActiveInterfaces", options
.sep
,
1433 "AvailableInterfaces", options
.sep
,
1434 "ConfiguredInterfaces", options
.sep
);
1440 printf("Public IPs on ALL nodes\n");
1442 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1446 for (i
= 0; i
< ips
->num
; i
++) {
1448 if (options
.machinereadable
== 1) {
1449 printf("%s%s%s%d%s", options
.sep
,
1450 ctdb_sock_addr_to_string(
1451 mem_ctx
, &ips
->ip
[i
].addr
),
1453 (int)ips
->ip
[i
].pnn
, options
.sep
);
1455 printf("%s", ctdb_sock_addr_to_string(
1456 mem_ctx
, &ips
->ip
[i
].addr
));
1459 if (options
.verbose
== 0) {
1460 if (options
.machinereadable
== 1) {
1463 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1472 if (ipinfo
[i
] == NULL
) {
1476 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1477 struct ctdb_iface
*iface
;
1479 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1481 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1483 conf
= talloc_asprintf_append(
1484 conf
, ",%s", iface
->name
);
1487 if (ipinfo
[i
]->active_idx
== j
) {
1488 active
= iface
->name
;
1491 if (iface
->link_state
== 0) {
1495 if (avail
== NULL
) {
1496 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1498 avail
= talloc_asprintf_append(
1499 avail
, ",%s", iface
->name
);
1505 if (options
.machinereadable
== 1) {
1506 printf("%s%s%s%s%s%s\n",
1507 active
? active
: "", options
.sep
,
1508 avail
? avail
: "", options
.sep
,
1509 conf
? conf
: "", options
.sep
);
1511 printf(" node[%d] active[%s] available[%s]"
1512 " configured[%s]\n",
1513 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1514 avail
? avail
: "", conf
? conf
: "");
1519 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1520 size_t datalen
, void *private_data
)
1522 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1523 private_data
, struct ctdb_public_ip_list
);
1524 struct ctdb_public_ip
*ip
;
1526 ip
= (struct ctdb_public_ip
*)databuf
;
1527 ips
->ip
[ips
->num
] = *ip
;
1533 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1534 struct ctdb_public_ip_list
**out
)
1536 struct ctdb_node_map
*nodemap
;
1537 struct ctdb_public_ip_list
*ips
;
1538 struct db_hash_context
*ipdb
;
1540 int ret
, count
, i
, j
;
1542 nodemap
= get_nodemap(ctdb
, false);
1543 if (nodemap
== NULL
) {
1547 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1552 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1558 for (i
=0; i
<count
; i
++) {
1559 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1560 pnn_list
[i
], TIMEOUT(),
1566 for (j
=0; j
<ips
->num
; j
++) {
1567 struct ctdb_public_ip ip
;
1569 ip
.pnn
= ips
->ip
[j
].pnn
;
1570 ip
.addr
= ips
->ip
[j
].addr
;
1572 if (pnn_list
[i
] == ip
.pnn
) {
1573 /* Node claims IP is hosted on it, so
1574 * save that information
1576 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1578 (uint8_t *)&ip
, sizeof(ip
));
1583 /* Node thinks IP is hosted elsewhere,
1584 * so overwrite with CTDB_UNKNOWN_PNN
1585 * if there's no existing entry
1587 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1589 if (ret
== ENOENT
) {
1590 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1591 ret
= db_hash_add(ipdb
,
1592 (uint8_t *)&ip
.addr
,
1606 talloc_free(pnn_list
);
1608 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1613 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1618 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1619 if (ips
->ip
== NULL
) {
1623 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1628 if (count
!= ips
->num
) {
1642 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1643 int argc
, const char **argv
)
1645 struct ctdb_public_ip_list
*ips
;
1646 struct ctdb_public_ip_info
**ipinfo
;
1648 bool do_all
= false;
1655 if (strcmp(argv
[0], "all") == 0) {
1663 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1665 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1666 ctdb
->cmd_pnn
, TIMEOUT(),
1673 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1674 ctdb_public_ip_cmp
);
1676 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1677 if (ipinfo
== NULL
) {
1681 for (i
=0; i
<ips
->num
; i
++) {
1684 pnn
= ips
->ip
[i
].pnn
;
1686 pnn
= ctdb
->cmd_pnn
;
1688 if (pnn
== CTDB_UNKNOWN_PNN
) {
1692 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1694 TIMEOUT(), &ips
->ip
[i
].addr
,
1701 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1705 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1706 int argc
, const char **argv
)
1708 struct ctdb_public_ip_info
*ipinfo
;
1709 ctdb_sock_addr addr
;
1716 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
1717 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1721 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1722 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1726 printf("Node %u does not know about IP %s\n",
1727 ctdb
->cmd_pnn
, argv
[0]);
1732 printf("Public IP[%s] info on node %u\n",
1733 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
),
1736 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1737 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
),
1738 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1740 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1741 struct ctdb_iface
*iface
;
1743 iface
= &ipinfo
->ifaces
->iface
[i
];
1744 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1745 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1747 iface
->link_state
== 0 ? "down" : "up",
1749 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1755 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1756 int argc
, const char **argv
)
1758 struct ctdb_iface_list
*ifaces
;
1765 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1766 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1771 if (ifaces
->num
== 0) {
1772 printf("No interfaces configured on node %u\n",
1777 if (options
.machinereadable
) {
1778 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1779 "Name", options
.sep
,
1780 "LinkStatus", options
.sep
,
1781 "References", options
.sep
);
1783 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1786 for (i
=0; i
<ifaces
->num
; i
++) {
1787 if (options
.machinereadable
) {
1788 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1789 ifaces
->iface
[i
].name
, options
.sep
,
1790 ifaces
->iface
[i
].link_state
, options
.sep
,
1791 ifaces
->iface
[i
].references
, options
.sep
);
1793 printf("name:%s link:%s references:%u\n",
1794 ifaces
->iface
[i
].name
,
1795 ifaces
->iface
[i
].link_state
? "up" : "down",
1796 ifaces
->iface
[i
].references
);
1803 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1804 int argc
, const char **argv
)
1806 struct ctdb_iface_list
*ifaces
;
1807 struct ctdb_iface
*iface
;
1811 usage("setifacelink");
1814 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1815 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1819 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1820 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1823 "Failed to get interface information from node %u\n",
1829 for (i
=0; i
<ifaces
->num
; i
++) {
1830 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1831 iface
= &ifaces
->iface
[i
];
1836 if (iface
== NULL
) {
1837 printf("Interface %s not configured on node %u\n",
1838 argv
[0], ctdb
->cmd_pnn
);
1842 if (strcmp(argv
[1], "up") == 0) {
1843 iface
->link_state
= 1;
1844 } else if (strcmp(argv
[1], "down") == 0) {
1845 iface
->link_state
= 0;
1847 usage("setifacelink");
1851 iface
->references
= 0;
1853 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1854 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
1862 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
1863 struct ctdb_context
*ctdb
,
1864 int argc
, const char **argv
)
1870 usage("process-exists");
1873 pid
= atoi(argv
[0]);
1874 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1875 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
1881 printf("PID %u exists\n", pid
);
1883 printf("PID %u does not exist\n", pid
);
1888 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1889 int argc
, const char **argv
)
1891 struct ctdb_dbid_map
*dbmap
;
1898 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1899 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
1904 if (options
.machinereadable
== 1) {
1905 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1908 "Name", options
.sep
,
1909 "Path", options
.sep
,
1910 "Persistent", options
.sep
,
1911 "Sticky", options
.sep
,
1912 "Unhealthy", options
.sep
,
1913 "Readonly", options
.sep
,
1914 "Replicated", options
.sep
);
1916 printf("Number of databases:%d\n", dbmap
->num
);
1919 for (i
=0; i
<dbmap
->num
; i
++) {
1929 db_id
= dbmap
->dbs
[i
].db_id
;
1931 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1932 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1938 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1939 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1945 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1946 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
1952 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
1953 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
1954 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
1955 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
1957 if (options
.machinereadable
== 1) {
1958 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
1963 !! (persistent
), options
.sep
,
1964 !! (sticky
), options
.sep
,
1965 !! (health
), options
.sep
,
1966 !! (readonly
), options
.sep
,
1967 !! (replicated
), options
.sep
);
1969 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
1971 persistent
? " PERSISTENT" : "",
1972 sticky
? " STICKY" : "",
1973 readonly
? " READONLY" : "",
1974 replicated
? " REPLICATED" : "",
1975 health
? " UNHEALTHY" : "");
1978 talloc_free(discard_const(name
));
1979 talloc_free(discard_const(path
));
1980 talloc_free(discard_const(health
));
1986 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1987 int argc
, const char **argv
)
1990 const char *db_name
, *db_path
, *db_health
;
1995 usage("getdbstatus");
1998 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2002 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2003 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2009 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2010 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2016 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2017 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2018 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2019 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2020 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2021 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2022 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2026 struct dump_record_state
{
2030 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2032 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2036 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2037 for (i
=0; i
<val
.dsize
; i
++) {
2038 if (ISASCII(val
.dptr
[i
])) {
2039 fprintf(stdout
, "%c", val
.dptr
[i
]);
2041 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2044 fprintf(stdout
, "\"\n");
2047 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2049 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2050 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2051 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2052 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2053 fprintf(stdout
, " MIGRATED_WITH_DATA");
2055 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2056 fprintf(stdout
, " VACUUM_MIGRATED");
2058 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2059 fprintf(stdout
, " AUTOMATIC");
2061 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2062 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2064 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2065 fprintf(stdout
, " RO_HAVE_READONLY");
2067 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2068 fprintf(stdout
, " RO_REVOKING_READONLY");
2070 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2071 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2073 fprintf(stdout
, "\n");
2077 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2078 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2080 struct dump_record_state
*state
=
2081 (struct dump_record_state
*)private_data
;
2085 dump_tdb_data("key", key
);
2086 dump_ltdb_header(header
);
2087 dump_tdb_data("data", data
);
2088 fprintf(stdout
, "\n");
2093 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2094 int argc
, const char **argv
)
2096 struct ctdb_db_context
*db
;
2097 const char *db_name
;
2100 struct dump_record_state state
;
2107 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2111 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2114 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2120 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2121 ctdb
->cmd_pnn
, TIMEOUT(),
2122 dump_record
, &state
);
2124 printf("Dumped %u records\n", state
.count
);
2129 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2130 int argc
, const char **argv
)
2132 struct ctdb_db_context
*db
;
2133 const char *db_name
;
2136 struct dump_record_state state
;
2143 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2147 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2150 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2155 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2157 printf("Dumped %u record(s)\n", state
.count
);
2162 static int control_getmonmode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2163 int argc
, const char **argv
)
2168 usage("getmonmode");
2171 ret
= ctdb_ctrl_get_monmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2172 ctdb
->cmd_pnn
, TIMEOUT(), &mode
);
2178 (mode
== CTDB_MONITORING_ENABLED
) ? "ENABLED" : "DISABLED");
2182 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2183 struct ctdb_context
*ctdb
,
2184 int argc
, const char **argv
)
2190 usage("getcapabilities");
2193 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2194 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2199 if (options
.machinereadable
== 1) {
2200 printf("%s%s%s%s%s\n",
2202 "RECMASTER", options
.sep
,
2203 "LMASTER", options
.sep
);
2204 printf("%s%d%s%d%s\n", options
.sep
,
2205 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2206 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2208 printf("RECMASTER: %s\n",
2209 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2210 printf("LMASTER: %s\n",
2211 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2217 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2218 int argc
, const char **argv
)
2220 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2224 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2225 int argc
, const char **argv
)
2227 char *t
, *lvs_helper
= NULL
;
2233 t
= getenv("CTDB_LVS_HELPER");
2235 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2237 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2238 CTDB_HELPER_BINDIR
);
2241 if (lvs_helper
== NULL
) {
2242 fprintf(stderr
, "Unable to set LVS helper\n");
2246 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2249 static int control_disable_monitor(TALLOC_CTX
*mem_ctx
,
2250 struct ctdb_context
*ctdb
,
2251 int argc
, const char **argv
)
2256 usage("disablemonitor");
2259 ret
= ctdb_ctrl_disable_monitor(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2260 ctdb
->cmd_pnn
, TIMEOUT());
2268 static int control_enable_monitor(TALLOC_CTX
*mem_ctx
,
2269 struct ctdb_context
*ctdb
,
2270 int argc
, const char **argv
)
2275 usage("enablemonitor");
2278 ret
= ctdb_ctrl_enable_monitor(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2279 ctdb
->cmd_pnn
, TIMEOUT());
2287 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2288 int argc
, const char **argv
)
2298 found
= debug_level_parse(argv
[0], &log_level
);
2301 "Invalid debug level '%s'. Valid levels are:\n",
2303 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2307 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2308 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2316 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2317 int argc
, const char **argv
)
2320 const char *log_str
;
2327 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2328 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2333 log_str
= debug_level_to_string(loglevel
);
2334 printf("%s\n", log_str
);
2339 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2340 int argc
, const char **argv
)
2342 const char *db_name
;
2343 uint8_t db_flags
= 0;
2346 if (argc
< 1 || argc
> 2) {
2352 if (strcmp(argv
[1], "persistent") == 0) {
2353 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2354 } else if (strcmp(argv
[1], "readonly") == 0) {
2355 db_flags
= CTDB_DB_FLAGS_READONLY
;
2356 } else if (strcmp(argv
[1], "sticky") == 0) {
2357 db_flags
= CTDB_DB_FLAGS_STICKY
;
2358 } else if (strcmp(argv
[1], "replicated") == 0) {
2359 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2365 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2374 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2375 int argc
, const char **argv
)
2377 const char *db_name
;
2380 struct ctdb_node_map
*nodemap
;
2388 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2389 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2394 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2395 fprintf(stderr
, "Database cannot be detached"
2396 " when recovery is active\n");
2400 nodemap
= get_nodemap(ctdb
, false);
2401 if (nodemap
== NULL
) {
2405 for (i
=0; i
<nodemap
->num
; i
++) {
2408 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
2411 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
2414 if (nodemap
->node
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2415 fprintf(stderr
, "Database cannot be detached on"
2416 " inactive (stopped or banned) node %u\n",
2417 nodemap
->node
[i
].pnn
);
2421 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2422 nodemap
->node
[i
].pnn
, TIMEOUT(),
2423 "AllowClientDBAttach", &value
);
2426 "Unable to get tunable AllowClientDBAttach"
2427 " from node %u\n", nodemap
->node
[i
].pnn
);
2433 "Database access is still active on node %u."
2434 " Set AllowclientDBAttach=0 on all nodes.\n",
2435 nodemap
->node
[i
].pnn
);
2441 for (i
=0; i
<argc
; i
++) {
2442 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2448 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2450 "Only volatile databases can be detached\n");
2454 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2456 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2464 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2465 int argc
, const char **argv
)
2467 const char *mem_str
;
2471 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2472 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2477 n
= write(1, mem_str
, strlen(mem_str
)+1);
2478 if (n
< 0 || n
!= strlen(mem_str
)+1) {
2479 fprintf(stderr
, "Failed to write talloc summary\n");
2486 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2488 bool *done
= (bool *)private_data
;
2491 n
= write(1, data
.dptr
, data
.dsize
);
2492 if (n
< 0 || n
!= data
.dsize
) {
2493 fprintf(stderr
, "Failed to write talloc summary\n");
2499 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2500 int argc
, const char **argv
)
2502 struct ctdb_srvid_message msg
= { 0 };
2506 msg
.pnn
= ctdb
->pnn
;
2507 msg
.srvid
= next_srvid(ctdb
);
2509 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2510 msg
.srvid
, dump_memory
, &done
);
2515 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2516 ctdb
->cmd_pnn
, &msg
);
2521 ctdb_client_wait(ctdb
->ev
, &done
);
2525 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2526 int argc
, const char **argv
)
2531 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2532 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2537 printf("%u\n", pid
);
2541 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2542 const char *desc
, uint32_t flag
, bool set_flag
)
2544 struct ctdb_node_map
*nodemap
;
2547 nodemap
= get_nodemap(ctdb
, false);
2548 if (nodemap
== NULL
) {
2552 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2553 if (set_flag
== flag_is_set
) {
2555 fprintf(stderr
, "Node %u is already %s\n",
2556 ctdb
->cmd_pnn
, desc
);
2558 fprintf(stderr
, "Node %u is not %s\n",
2559 ctdb
->cmd_pnn
, desc
);
2567 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2568 uint32_t flag
, bool set_flag
)
2570 struct ctdb_node_map
*nodemap
;
2574 nodemap
= get_nodemap(ctdb
, true);
2575 if (nodemap
== NULL
) {
2577 "Failed to get nodemap, trying again\n");
2582 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2583 if (flag_is_set
== set_flag
) {
2591 static int ctdb_ctrl_modflags(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
2592 struct ctdb_client_context
*client
,
2593 uint32_t destnode
, struct timeval timeout
,
2594 uint32_t set
, uint32_t clear
)
2596 struct ctdb_node_map
*nodemap
;
2597 struct ctdb_node_flag_change flag_change
;
2598 struct ctdb_req_control request
;
2602 ret
= ctdb_ctrl_get_nodemap(mem_ctx
, ev
, client
, destnode
,
2603 tevent_timeval_zero(), &nodemap
);
2608 flag_change
.pnn
= destnode
;
2609 flag_change
.old_flags
= nodemap
->node
[destnode
].flags
;
2610 flag_change
.new_flags
= flag_change
.old_flags
| set
;
2611 flag_change
.new_flags
&= ~clear
;
2613 count
= list_of_connected_nodes(nodemap
, -1, mem_ctx
, &pnn_list
);
2618 ctdb_req_control_modify_flags(&request
, &flag_change
);
2619 ret
= ctdb_client_control_multi(mem_ctx
, ev
, client
, pnn_list
, count
,
2620 tevent_timeval_zero(), &request
,
2625 struct ipreallocate_state
{
2630 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2633 struct ipreallocate_state
*state
=
2634 (struct ipreallocate_state
*)private_data
;
2636 if (data
.dsize
!= sizeof(int)) {
2641 state
->status
= *(int *)data
.dptr
;
2645 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2647 struct ctdb_srvid_message msg
= { 0 };
2648 struct ipreallocate_state state
;
2651 msg
.pnn
= ctdb
->pnn
;
2652 msg
.srvid
= next_srvid(ctdb
);
2655 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2657 ipreallocate_handler
, &state
);
2663 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2665 CTDB_BROADCAST_CONNECTED
,
2671 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2677 if (state
.status
>= 0) {
2686 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2691 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2692 int argc
, const char **argv
)
2700 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2701 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2706 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2707 ctdb
->cmd_pnn
, TIMEOUT(),
2708 NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2711 "Failed to set DISABLED flag on node %u\n",
2716 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2717 return ipreallocate(mem_ctx
, ctdb
);
2720 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2721 int argc
, const char **argv
)
2729 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2730 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2735 ret
= ctdb_ctrl_modflags(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2736 ctdb
->cmd_pnn
, TIMEOUT(),
2737 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2739 fprintf(stderr
, "Failed to reset DISABLED flag on node %u\n",
2744 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2745 return ipreallocate(mem_ctx
, ctdb
);
2748 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2749 int argc
, const char **argv
)
2757 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2758 NODE_FLAGS_STOPPED
, true);
2763 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2764 ctdb
->cmd_pnn
, TIMEOUT());
2766 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2770 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2771 return ipreallocate(mem_ctx
, ctdb
);
2774 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2775 int argc
, const char **argv
)
2783 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2784 NODE_FLAGS_STOPPED
, false);
2789 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2790 ctdb
->cmd_pnn
, TIMEOUT());
2792 fprintf(stderr
, "Failed to continue stopped node %u\n",
2797 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2798 return ipreallocate(mem_ctx
, ctdb
);
2801 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2802 int argc
, const char **argv
)
2804 struct ctdb_ban_state ban_state
;
2811 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2812 NODE_FLAGS_BANNED
, true);
2817 ban_state
.pnn
= ctdb
->cmd_pnn
;
2818 ban_state
.time
= strtoul(argv
[0], NULL
, 0);
2820 if (ban_state
.time
== 0) {
2821 fprintf(stderr
, "Ban time cannot be zero\n");
2825 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2826 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2828 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2832 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2833 return ipreallocate(mem_ctx
, ctdb
);
2837 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2838 int argc
, const char **argv
)
2840 struct ctdb_ban_state ban_state
;
2847 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2848 NODE_FLAGS_BANNED
, false);
2853 ban_state
.pnn
= ctdb
->cmd_pnn
;
2856 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2857 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2859 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2863 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2864 return ipreallocate(mem_ctx
, ctdb
);
2868 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2869 int argc
, const char **argv
)
2877 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2878 ctdb
->cmd_pnn
, TIMEOUT());
2880 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
2887 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2888 uint32_t *generation
)
2892 struct ctdb_vnn_map
*vnnmap
;
2896 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2897 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
2899 fprintf(stderr
, "Failed to find recovery master\n");
2903 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2904 recmaster
, TIMEOUT(), &recmode
);
2906 fprintf(stderr
, "Failed to get recovery mode from node %u\n",
2911 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2916 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2917 recmaster
, TIMEOUT(), &vnnmap
);
2919 fprintf(stderr
, "Failed to get generation from node %u\n",
2924 if (vnnmap
->generation
== INVALID_GENERATION
) {
2925 talloc_free(vnnmap
);
2930 *generation
= vnnmap
->generation
;
2931 talloc_free(vnnmap
);
2936 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2937 int argc
, const char **argv
)
2939 uint32_t generation
, next_generation
;
2946 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
2951 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2952 ctdb
->cmd_pnn
, TIMEOUT(),
2953 CTDB_RECOVERY_ACTIVE
);
2955 fprintf(stderr
, "Failed to set recovery mode active\n");
2960 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
2963 "Failed to confirm end of recovery\n");
2967 if (next_generation
!= generation
) {
2977 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2978 int argc
, const char **argv
)
2981 usage("ipreallocate");
2984 return ipreallocate(mem_ctx
, ctdb
);
2987 static int control_isnotrecmaster(TALLOC_CTX
*mem_ctx
,
2988 struct ctdb_context
*ctdb
,
2989 int argc
, const char **argv
)
2995 usage("isnotrecmaster");
2998 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2999 ctdb
->pnn
, TIMEOUT(), &recmaster
);
3001 fprintf(stderr
, "Failed to get recmaster\n");
3005 if (recmaster
!= ctdb
->pnn
) {
3006 printf("this node is not the recmaster\n");
3010 printf("this node is the recmaster\n");
3014 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3015 int argc
, const char **argv
)
3017 struct ctdb_addr_info addr_info
;
3024 if (! parse_ip(argv
[0], NULL
, 0, &addr_info
.addr
)) {
3025 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3028 addr_info
.iface
= argv
[1];
3030 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3031 ctdb
->cmd_pnn
, TIMEOUT(),
3034 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3042 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3043 int argc
, const char **argv
)
3045 ctdb_sock_addr src
, dst
;
3048 if (argc
!= 0 && argc
!= 2) {
3053 struct ctdb_connection
*clist
;
3057 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3063 for (i
=0; i
<count
; i
++) {
3064 ret
= ctdb_sys_send_tcp(&clist
[i
].src
,
3074 if (num_failed
> 0) {
3075 fprintf(stderr
, "Failed to send %d tickles\n",
3084 if (! parse_ip_port(argv
[0], &src
)) {
3085 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3089 if (! parse_ip_port(argv
[1], &dst
)) {
3090 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3094 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3096 fprintf(stderr
, "Failed to send tickle ack\n");
3103 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3104 int argc
, const char **argv
)
3106 ctdb_sock_addr addr
;
3107 struct ctdb_tickle_list
*tickles
;
3111 if (argc
< 1 || argc
> 2) {
3112 usage("gettickles");
3116 port
= strtoul(argv
[1], NULL
, 10);
3119 if (! parse_ip(argv
[0], NULL
, port
, &addr
)) {
3120 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3124 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3125 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3128 fprintf(stderr
, "Failed to get list of connections\n");
3132 if (options
.machinereadable
) {
3133 printf("%s%s%s%s%s%s%s%s%s\n",
3135 "Source IP", options
.sep
,
3136 "Port", options
.sep
,
3137 "Destiation IP", options
.sep
,
3138 "Port", options
.sep
);
3139 for (i
=0; i
<tickles
->num
; i
++) {
3140 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3141 ctdb_sock_addr_to_string(
3142 mem_ctx
, &tickles
->conn
[i
].src
),
3144 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3146 ctdb_sock_addr_to_string(
3147 mem_ctx
, &tickles
->conn
[i
].dst
),
3149 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3153 printf("Connections for IP: %s\n",
3154 ctdb_sock_addr_to_string(mem_ctx
, &tickles
->addr
));
3155 printf("Num connections: %u\n", tickles
->num
);
3156 for (i
=0; i
<tickles
->num
; i
++) {
3157 printf("SRC: %s:%u DST: %s:%u\n",
3158 ctdb_sock_addr_to_string(
3159 mem_ctx
, &tickles
->conn
[i
].src
),
3160 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3161 ctdb_sock_addr_to_string(
3162 mem_ctx
, &tickles
->conn
[i
].dst
),
3163 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
));
3167 talloc_free(tickles
);
3171 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3172 struct ctdb_connection
*conn
);
3174 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3176 struct process_clist_state
{
3177 struct ctdb_connection
*clist
;
3179 int num_failed
, num_total
;
3180 clist_reply_func reply_func
;
3183 static void process_clist_done(struct tevent_req
*subreq
);
3185 static struct tevent_req
*process_clist_send(
3186 TALLOC_CTX
*mem_ctx
,
3187 struct ctdb_context
*ctdb
,
3188 struct ctdb_connection
*clist
,
3190 clist_request_func request_func
,
3191 clist_reply_func reply_func
)
3193 struct tevent_req
*req
, *subreq
;
3194 struct process_clist_state
*state
;
3195 struct ctdb_req_control request
;
3198 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3203 state
->clist
= clist
;
3204 state
->count
= count
;
3205 state
->reply_func
= reply_func
;
3207 for (i
=0; i
<count
; i
++) {
3208 request_func(&request
, &clist
[i
]);
3209 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3210 ctdb
->client
, ctdb
->cmd_pnn
,
3211 TIMEOUT(), &request
);
3212 if (tevent_req_nomem(subreq
, req
)) {
3213 return tevent_req_post(req
, ctdb
->ev
);
3215 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3221 static void process_clist_done(struct tevent_req
*subreq
)
3223 struct tevent_req
*req
= tevent_req_callback_data(
3224 subreq
, struct tevent_req
);
3225 struct process_clist_state
*state
= tevent_req_data(
3226 req
, struct process_clist_state
);
3227 struct ctdb_reply_control
*reply
;
3231 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3232 TALLOC_FREE(subreq
);
3234 state
->num_failed
+= 1;
3238 ret
= state
->reply_func(reply
);
3240 state
->num_failed
+= 1;
3245 state
->num_total
+= 1;
3246 if (state
->num_total
== state
->count
) {
3247 tevent_req_done(req
);
3251 static int process_clist_recv(struct tevent_req
*req
)
3253 struct process_clist_state
*state
= tevent_req_data(
3254 req
, struct process_clist_state
);
3256 return state
->num_failed
;
3259 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3260 int argc
, const char **argv
)
3262 struct ctdb_connection conn
;
3265 if (argc
!= 0 && argc
!= 2) {
3270 struct ctdb_connection
*clist
;
3271 struct tevent_req
*req
;
3274 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3282 req
= process_clist_send(mem_ctx
, ctdb
, clist
, count
,
3283 ctdb_req_control_tcp_add_delayed_update
,
3284 ctdb_reply_control_tcp_add_delayed_update
);
3290 tevent_req_poll(req
, ctdb
->ev
);
3293 ret
= process_clist_recv(req
);
3295 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3302 if (! parse_ip_port(argv
[0], &conn
.src
)) {
3303 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3306 if (! parse_ip_port(argv
[1], &conn
.dst
)) {
3307 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3311 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3312 ctdb
->client
, ctdb
->cmd_pnn
,
3315 fprintf(stderr
, "Failed to register connection\n");
3322 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3323 int argc
, const char **argv
)
3325 struct ctdb_connection conn
;
3328 if (argc
!= 0 && argc
!= 2) {
3333 struct ctdb_connection
*clist
;
3334 struct tevent_req
*req
;
3337 ret
= ctdb_parse_connections(stdin
, mem_ctx
, &count
, &clist
);
3345 req
= process_clist_send(mem_ctx
, ctdb
, clist
, count
,
3346 ctdb_req_control_tcp_remove
,
3347 ctdb_reply_control_tcp_remove
);
3353 tevent_req_poll(req
, ctdb
->ev
);
3356 ret
= process_clist_recv(req
);
3358 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3365 if (! parse_ip_port(argv
[0], &conn
.src
)) {
3366 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3369 if (! parse_ip_port(argv
[1], &conn
.dst
)) {
3370 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3374 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3375 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3377 fprintf(stderr
, "Failed to unregister connection\n");
3384 static int control_check_srvids(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3385 int argc
, const char **argv
)
3392 usage("check_srvids");
3395 srvid
= talloc_array(mem_ctx
, uint64_t, argc
);
3396 if (srvid
== NULL
) {
3397 fprintf(stderr
, "Memory allocation error\n");
3401 for (i
=0; i
<argc
; i
++) {
3402 srvid
[i
] = strtoull(argv
[i
], NULL
, 0);
3405 ret
= ctdb_ctrl_check_srvids(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3406 ctdb
->cmd_pnn
, TIMEOUT(), srvid
, argc
,
3409 fprintf(stderr
, "Failed to check srvids on node %u\n",
3414 for (i
=0; i
<argc
; i
++) {
3415 printf("SRVID 0x%" PRIx64
" %s\n", srvid
[i
],
3416 (result
[i
] ? "exists" : "does not exist"));
3422 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3423 int argc
, const char **argv
)
3425 struct ctdb_node_map
*nodemap
;
3432 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3433 if (nodemap
== NULL
) {
3437 for (i
=0; i
<nodemap
->num
; i
++) {
3438 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3442 if (options
.machinereadable
) {
3443 printf("%s%u%s%s%s\n", options
.sep
,
3444 nodemap
->node
[i
].pnn
, options
.sep
,
3445 ctdb_sock_addr_to_string(
3446 mem_ctx
, &nodemap
->node
[i
].addr
),
3450 ctdb_sock_addr_to_string(
3451 mem_ctx
, &nodemap
->node
[i
].addr
));
3458 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3459 struct ctdb_node_map
*nodemap2
)
3463 if (nodemap1
->num
!= nodemap2
->num
) {
3467 for (i
=0; i
<nodemap1
->num
; i
++) {
3468 struct ctdb_node_and_flags
*n1
, *n2
;
3470 n1
= &nodemap1
->node
[i
];
3471 n2
= &nodemap2
->node
[i
];
3473 if ((n1
->pnn
!= n2
->pnn
) ||
3474 (n1
->flags
!= n2
->flags
) ||
3475 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3483 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3484 struct ctdb_node_map
*nm
,
3485 struct ctdb_node_map
*fnm
,
3489 bool check_failed
= false;
3493 for (i
=0; i
<nm
->num
; i
++) {
3494 if (i
>= fnm
->num
) {
3496 "Node %u (%s) missing from nodes file\n",
3498 ctdb_sock_addr_to_string(
3499 mem_ctx
, &nm
->node
[i
].addr
));
3500 check_failed
= true;
3503 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3504 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3505 /* Node remains deleted */
3509 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3510 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3511 /* Node not newly nor previously deleted */
3512 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3513 &fnm
->node
[i
].addr
)) {
3515 "Node %u has changed IP address"
3516 " (was %s, now %s)\n",
3518 ctdb_sock_addr_to_string(
3519 mem_ctx
, &nm
->node
[i
].addr
),
3520 ctdb_sock_addr_to_string(
3521 mem_ctx
, &fnm
->node
[i
].addr
));
3522 check_failed
= true;
3524 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3526 "WARNING: Node %u is disconnected."
3527 " You MUST fix this node manually!\n",
3534 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3535 /* Node is being deleted */
3536 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3538 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3540 "ERROR: Node %u is still connected\n",
3542 check_failed
= true;
3547 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3548 /* Node was previously deleted */
3549 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3556 "ERROR: Nodes will not be reloaded due to previous error\n");
3560 /* Leftover nodes in file are NEW */
3561 for (; i
< fnm
->num
; i
++) {
3562 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3569 struct disable_recoveries_state
{
3577 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3580 struct disable_recoveries_state
*state
=
3581 (struct disable_recoveries_state
*)private_data
;
3584 if (data
.dsize
!= sizeof(int)) {
3589 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3590 ret
= *(int *)data
.dptr
;
3592 state
->status
= ret
;
3596 for (i
=0; i
<state
->node_count
; i
++) {
3597 if (state
->pnn_list
[i
] == ret
) {
3598 state
->reply
[i
] = true;
3604 for (i
=0; i
<state
->node_count
; i
++) {
3605 if (! state
->reply
[i
]) {
3606 state
->done
= false;
3612 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3613 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3615 struct ctdb_disable_message disable
= { 0 };
3616 struct disable_recoveries_state state
;
3619 disable
.pnn
= ctdb
->pnn
;
3620 disable
.srvid
= next_srvid(ctdb
);
3621 disable
.timeout
= timeout
;
3623 state
.pnn_list
= pnn_list
;
3624 state
.node_count
= count
;
3627 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3628 if (state
.reply
== NULL
) {
3632 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3634 disable_recoveries_handler
,
3640 for (i
=0; i
<count
; i
++) {
3641 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3650 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3652 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3654 ret
= (state
.status
>= 0 ? 0 : 1);
3658 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3659 disable
.srvid
, &state
);
3663 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3664 int argc
, const char **argv
)
3666 struct ctdb_node_map
*nodemap
= NULL
;
3667 struct ctdb_node_map
*file_nodemap
;
3668 struct ctdb_node_map
*remote_nodemap
;
3669 struct ctdb_req_control request
;
3670 struct ctdb_reply_control
**reply
;
3676 nodemap
= get_nodemap(ctdb
, false);
3677 if (nodemap
== NULL
) {
3681 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3682 if (file_nodemap
== NULL
) {
3686 for (i
=0; i
<nodemap
->num
; i
++) {
3687 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3691 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3692 nodemap
->node
[i
].pnn
, TIMEOUT(),
3696 "ERROR: Failed to get nodes file from node %u\n",
3697 nodemap
->node
[i
].pnn
);
3701 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3703 "ERROR: Nodes file on node %u differs"
3704 " from current node (%u)\n",
3705 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3710 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3716 fprintf(stderr
, "No change in nodes file,"
3717 " skipping unnecessary reload\n");
3721 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3722 mem_ctx
, &pnn_list
);
3724 fprintf(stderr
, "Memory allocation error\n");
3728 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3731 fprintf(stderr
, "Failed to disable recoveries\n");
3735 ctdb_req_control_reload_nodes_file(&request
);
3736 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3737 pnn_list
, count
, TIMEOUT(),
3738 &request
, NULL
, &reply
);
3740 bool failed
= false;
3742 for (i
=0; i
<count
; i
++) {
3743 ret
= ctdb_reply_control_reload_nodes_file(reply
[i
]);
3746 "Node %u failed to reload nodes\n",
3753 "You MUST fix failed nodes manually!\n");
3757 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3759 fprintf(stderr
, "Failed to enable recoveries\n");
3766 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3767 ctdb_sock_addr
*addr
, uint32_t pnn
)
3769 struct ctdb_public_ip_list
*pubip_list
;
3770 struct ctdb_public_ip pubip
;
3771 struct ctdb_node_map
*nodemap
;
3772 struct ctdb_req_control request
;
3776 ret
= ctdb_message_disable_ip_check(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3777 CTDB_BROADCAST_CONNECTED
,
3778 2*options
.timelimit
);
3780 fprintf(stderr
, "Failed to disable IP check\n");
3784 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3785 pnn
, TIMEOUT(), false, &pubip_list
);
3787 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3792 for (i
=0; i
<pubip_list
->num
; i
++) {
3793 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3798 if (i
== pubip_list
->num
) {
3799 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3800 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
));
3804 nodemap
= get_nodemap(ctdb
, false);
3805 if (nodemap
== NULL
) {
3809 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3811 fprintf(stderr
, "Memory allocation error\n");
3817 ctdb_req_control_release_ip(&request
, &pubip
);
3819 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3820 pnn_list
, count
, TIMEOUT(),
3821 &request
, NULL
, NULL
);
3823 fprintf(stderr
, "Failed to release IP on nodes\n");
3827 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3828 pnn
, TIMEOUT(), &pubip
);
3830 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3837 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3838 int argc
, const char **argv
)
3840 ctdb_sock_addr addr
;
3842 int ret
, retries
= 0;
3848 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
3849 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3853 pnn
= strtoul(argv
[1], NULL
, 10);
3854 if (pnn
== CTDB_UNKNOWN_PNN
) {
3855 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3859 while (retries
< 5) {
3860 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3870 fprintf(stderr
, "Failed to move IP %s to node %u\n",
3878 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3883 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3884 CTDB_BROADCAST_CONNECTED
, pnn
);
3887 "Failed to ask recovery master to distribute IPs\n");
3894 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3895 int argc
, const char **argv
)
3897 ctdb_sock_addr addr
;
3898 struct ctdb_public_ip_list
*pubip_list
;
3899 struct ctdb_addr_info addr_info
;
3901 int ret
, i
, retries
= 0;
3907 if (! parse_ip_mask(argv
[0], argv
[1], &addr
, &mask
)) {
3908 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
3912 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3913 ctdb
->cmd_pnn
, TIMEOUT(),
3914 false, &pubip_list
);
3916 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3921 for (i
=0; i
<pubip_list
->num
; i
++) {
3922 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3923 fprintf(stderr
, "Node already knows about IP %s\n",
3924 ctdb_sock_addr_to_string(mem_ctx
, &addr
));
3929 addr_info
.addr
= addr
;
3930 addr_info
.mask
= mask
;
3931 addr_info
.iface
= argv
[1];
3933 while (retries
< 5) {
3934 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3935 ctdb
->cmd_pnn
, TIMEOUT(),
3946 fprintf(stderr
, "Failed to add public IP to node %u."
3947 " Giving up\n", ctdb
->cmd_pnn
);
3951 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
3959 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3960 int argc
, const char **argv
)
3962 ctdb_sock_addr addr
;
3963 struct ctdb_public_ip_list
*pubip_list
;
3964 struct ctdb_addr_info addr_info
;
3971 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
3972 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3976 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3977 ctdb
->cmd_pnn
, TIMEOUT(),
3978 false, &pubip_list
);
3980 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3985 for (i
=0; i
<pubip_list
->num
; i
++) {
3986 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
3991 if (i
== pubip_list
->num
) {
3992 fprintf(stderr
, "Node does not know about IP address %s\n",
3993 ctdb_sock_addr_to_string(mem_ctx
, &addr
));
3997 addr_info
.addr
= addr
;
3999 addr_info
.iface
= NULL
;
4001 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4002 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
4004 fprintf(stderr
, "Failed to delete public IP from node %u\n",
4012 #define DB_VERSION 3
4013 #define MAX_DB_NAME 64
4014 #define MAX_REC_BUFFER_SIZE (100*1000)
4017 unsigned long version
;
4019 unsigned long flags
;
4022 char name
[MAX_DB_NAME
];
4025 struct backup_state
{
4026 TALLOC_CTX
*mem_ctx
;
4027 struct ctdb_rec_buffer
*recbuf
;
4030 unsigned int nbuf
, nrec
;
4033 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
4034 TDB_DATA key
, TDB_DATA data
, void *private_data
)
4036 struct backup_state
*state
= (struct backup_state
*)private_data
;
4040 if (state
->recbuf
== NULL
) {
4041 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4043 if (state
->recbuf
== NULL
) {
4048 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4054 len
= ctdb_rec_buffer_len(state
->recbuf
);
4055 if (len
< MAX_REC_BUFFER_SIZE
) {
4059 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4061 fprintf(stderr
, "Failed to write records to backup file\n");
4066 state
->nrec
+= state
->recbuf
->count
;
4067 TALLOC_FREE(state
->recbuf
);
4072 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4073 int argc
, const char **argv
)
4075 const char *db_name
;
4076 struct ctdb_db_context
*db
;
4079 struct backup_state state
;
4080 struct db_header db_hdr
;
4087 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4091 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4094 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4098 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4101 fprintf(stderr
, "Failed to open file %s for writing\n",
4106 /* Write empty header first */
4107 ZERO_STRUCT(db_hdr
);
4108 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4112 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4116 state
.mem_ctx
= mem_ctx
;
4117 state
.recbuf
= NULL
;
4122 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4124 fprintf(stderr
, "Failed to collect records from DB %s\n",
4130 if (state
.recbuf
!= NULL
) {
4131 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4134 "Failed to write records to backup file\n");
4140 state
.nrec
+= state
.recbuf
->count
;
4141 TALLOC_FREE(state
.recbuf
);
4144 db_hdr
.version
= DB_VERSION
;
4145 db_hdr
.timestamp
= time(NULL
);
4146 db_hdr
.flags
= db_flags
;
4147 db_hdr
.nbuf
= state
.nbuf
;
4148 db_hdr
.nrec
= state
.nrec
;
4149 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4151 lseek(fd
, 0, SEEK_SET
);
4152 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4156 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4161 printf("Database backed up to %s\n", argv
[1]);
4165 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4166 int argc
, const char **argv
)
4168 const char *db_name
= NULL
;
4169 struct ctdb_db_context
*db
;
4170 struct db_header db_hdr
;
4171 struct ctdb_node_map
*nodemap
;
4172 struct ctdb_req_control request
;
4173 struct ctdb_reply_control
**reply
;
4174 struct ctdb_transdb wipedb
;
4175 struct ctdb_pulldb_ext pulldb
;
4176 struct ctdb_rec_buffer
*recbuf
;
4177 uint32_t generation
;
4183 if (argc
< 1 || argc
> 2) {
4187 fd
= open(argv
[0], O_RDONLY
, 0600);
4190 fprintf(stderr
, "Failed to open file %s for reading\n",
4199 ret
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4203 fprintf(stderr
, "Failed to read db header from file %s\n",
4207 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4209 if (db_hdr
.version
!= DB_VERSION
) {
4211 "Wrong version of backup file, expected %u, got %lu\n",
4212 DB_VERSION
, db_hdr
.version
);
4217 if (db_name
== NULL
) {
4218 db_name
= db_hdr
.name
;
4221 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4222 localtime(&db_hdr
.timestamp
));
4223 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4225 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4228 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4233 nodemap
= get_nodemap(ctdb
, false);
4234 if (nodemap
== NULL
) {
4235 fprintf(stderr
, "Failed to get nodemap\n");
4240 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4242 fprintf(stderr
, "Failed to get current generation\n");
4247 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4254 wipedb
.db_id
= ctdb_db_id(db
);
4255 wipedb
.tid
= generation
;
4257 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4258 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4259 ctdb
->client
, pnn_list
, count
,
4260 TIMEOUT(), &request
, NULL
, NULL
);
4266 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4267 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4268 pnn_list
, count
, TIMEOUT(),
4269 &request
, NULL
, NULL
);
4274 ctdb_req_control_wipe_database(&request
, &wipedb
);
4275 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4276 pnn_list
, count
, TIMEOUT(),
4277 &request
, NULL
, NULL
);
4282 pulldb
.db_id
= ctdb_db_id(db
);
4284 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4286 ctdb_req_control_db_push_start(&request
, &pulldb
);
4287 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4288 pnn_list
, count
, TIMEOUT(),
4289 &request
, NULL
, NULL
);
4294 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4295 struct ctdb_req_message message
;
4298 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4303 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4304 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4305 if (data
.dptr
== NULL
) {
4309 ctdb_rec_buffer_push(recbuf
, data
.dptr
);
4311 message
.srvid
= pulldb
.srvid
;
4312 message
.data
.data
= data
;
4314 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4322 talloc_free(recbuf
);
4323 talloc_free(data
.dptr
);
4326 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4327 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4328 pnn_list
, count
, TIMEOUT(),
4329 &request
, NULL
, &reply
);
4334 for (i
=0; i
<count
; i
++) {
4335 uint32_t num_records
;
4337 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4340 fprintf(stderr
, "Invalid response from node %u\n",
4345 if (num_records
!= db_hdr
.nrec
) {
4346 fprintf(stderr
, "Node %u received %u of %lu records\n",
4347 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4352 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4353 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4354 pnn_list
, count
, TIMEOUT(),
4355 &request
, NULL
, NULL
);
4360 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4361 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4362 pnn_list
, count
, TIMEOUT(),
4363 &request
, NULL
, NULL
);
4368 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4369 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4370 ctdb
->client
, pnn_list
, count
,
4371 TIMEOUT(), &request
, NULL
, NULL
);
4376 printf("Database %s restored\n", db_name
);
4383 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4384 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4388 struct dumpdbbackup_state
{
4389 ctdb_rec_parser_func_t parser
;
4390 struct dump_record_state sub_state
;
4393 static int dumpdbbackup_handler(uint32_t reqid
,
4394 struct ctdb_ltdb_header
*header
,
4395 TDB_DATA key
, TDB_DATA data
,
4398 struct dumpdbbackup_state
*state
=
4399 (struct dumpdbbackup_state
*)private_data
;
4400 struct ctdb_ltdb_header hdr
;
4403 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4408 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4411 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4412 int argc
, const char **argv
)
4414 struct db_header db_hdr
;
4416 struct dumpdbbackup_state state
;
4420 usage("dumpbackup");
4423 fd
= open(argv
[0], O_RDONLY
, 0600);
4426 fprintf(stderr
, "Failed to open file %s for reading\n",
4431 ret
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4435 fprintf(stderr
, "Failed to read db header from file %s\n",
4439 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4441 if (db_hdr
.version
!= DB_VERSION
) {
4443 "Wrong version of backup file, expected %u, got %lu\n",
4444 DB_VERSION
, db_hdr
.version
);
4449 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4450 localtime(&db_hdr
.timestamp
));
4451 printf("Dumping database %s from backup @ %s\n",
4452 db_hdr
.name
, timebuf
);
4454 state
.parser
= dump_record
;
4455 state
.sub_state
.count
= 0;
4457 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4458 struct ctdb_rec_buffer
*recbuf
;
4460 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4462 fprintf(stderr
, "Failed to read records\n");
4467 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4470 fprintf(stderr
, "Failed to dump records\n");
4477 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4481 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4482 int argc
, const char **argv
)
4484 const char *db_name
;
4485 struct ctdb_db_context
*db
;
4488 struct ctdb_node_map
*nodemap
;
4489 struct ctdb_req_control request
;
4490 struct ctdb_transdb wipedb
;
4491 uint32_t generation
;
4499 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4503 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4506 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4510 nodemap
= get_nodemap(ctdb
, false);
4511 if (nodemap
== NULL
) {
4512 fprintf(stderr
, "Failed to get nodemap\n");
4516 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4518 fprintf(stderr
, "Failed to get current generation\n");
4522 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4528 ctdb_req_control_db_freeze(&request
, db_id
);
4529 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4530 ctdb
->client
, pnn_list
, count
,
4531 TIMEOUT(), &request
, NULL
, NULL
);
4536 wipedb
.db_id
= db_id
;
4537 wipedb
.tid
= generation
;
4539 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4540 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4541 pnn_list
, count
, TIMEOUT(),
4542 &request
, NULL
, NULL
);
4547 ctdb_req_control_wipe_database(&request
, &wipedb
);
4548 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4549 pnn_list
, count
, TIMEOUT(),
4550 &request
, NULL
, NULL
);
4555 ctdb_req_control_db_set_healthy(&request
, db_id
);
4556 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4557 pnn_list
, count
, TIMEOUT(),
4558 &request
, NULL
, NULL
);
4563 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4564 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4565 pnn_list
, count
, TIMEOUT(),
4566 &request
, NULL
, NULL
);
4571 ctdb_req_control_db_thaw(&request
, db_id
);
4572 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4573 ctdb
->client
, pnn_list
, count
,
4574 TIMEOUT(), &request
, NULL
, NULL
);
4579 printf("Database %s wiped\n", db_name
);
4584 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4585 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4589 static int control_recmaster(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4590 int argc
, const char **argv
)
4595 ret
= ctdb_ctrl_get_recmaster(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4596 ctdb
->cmd_pnn
, TIMEOUT(), &recmaster
);
4601 printf("%u\n", recmaster
);
4605 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4606 int argc
, const char **argv
)
4608 char *t
, *event_helper
= NULL
;
4609 char *eventd_socket
= NULL
;
4610 const char **new_argv
;
4613 t
= getenv("CTDB_EVENT_HELPER");
4615 event_helper
= talloc_strdup(mem_ctx
, t
);
4617 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_event",
4618 CTDB_HELPER_BINDIR
);
4621 if (event_helper
== NULL
) {
4622 fprintf(stderr
, "Unable to set event daemon helper\n");
4626 t
= getenv("CTDB_SOCKET");
4628 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4631 eventd_socket
= talloc_asprintf(mem_ctx
, "%s/eventd.sock",
4635 if (eventd_socket
== NULL
) {
4636 fprintf(stderr
, "Unable to set event daemon socket\n");
4640 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 1);
4641 if (new_argv
== NULL
) {
4642 fprintf(stderr
, "Memory allocation error\n");
4646 new_argv
[0] = eventd_socket
;
4647 for (i
=0; i
<argc
; i
++) {
4648 new_argv
[i
+1] = argv
[i
];
4651 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4655 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4656 int argc
, const char **argv
)
4658 const char *new_argv
[3];
4661 usage("scriptstatus");
4664 new_argv
[0] = "status";
4665 new_argv
[1] = (argc
== 0) ? "monitor" : argv
[0];
4668 (void) control_event(mem_ctx
, ctdb
, 2, new_argv
);
4672 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4673 int argc
, const char **argv
)
4675 char *t
, *natgw_helper
= NULL
;
4681 t
= getenv("CTDB_NATGW_HELPER");
4683 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4685 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4686 CTDB_HELPER_BINDIR
);
4689 if (natgw_helper
== NULL
) {
4690 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4694 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4698 static int control_natgwlist(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4699 int argc
, const char **argv
)
4701 char *t
, *natgw_helper
= NULL
;
4702 const char *cmd_argv
[] = { "natgwlist", NULL
};
4708 t
= getenv("CTDB_NATGW_HELPER");
4710 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4712 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4713 CTDB_HELPER_BINDIR
);
4716 if (natgw_helper
== NULL
) {
4717 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4721 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4726 * Find the PNN of the current node
4727 * discover the pnn by loading the nodes file and try to bind
4728 * to all addresses one at a time until the ip address is found.
4730 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4732 struct ctdb_node_map
*nodemap
;
4735 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4736 if (nodemap
== NULL
) {
4740 for (i
=0; i
<nodemap
->num
; i
++) {
4741 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4744 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4746 *pnn
= nodemap
->node
[i
].pnn
;
4748 talloc_free(nodemap
);
4753 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4754 talloc_free(nodemap
);
4758 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4759 int argc
, const char **argv
)
4761 const char *reclock
;
4765 usage("getreclock");
4768 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4769 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4774 if (reclock
!= NULL
) {
4775 printf("%s\n", reclock
);
4781 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4782 struct ctdb_context
*ctdb
,
4783 int argc
, const char **argv
)
4785 uint32_t lmasterrole
= 0;
4789 usage("setlmasterrole");
4792 if (strcmp(argv
[0], "on") == 0) {
4794 } else if (strcmp(argv
[0], "off") == 0) {
4797 usage("setlmasterrole");
4800 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4801 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4809 static int control_setrecmasterrole(TALLOC_CTX
*mem_ctx
,
4810 struct ctdb_context
*ctdb
,
4811 int argc
, const char **argv
)
4813 uint32_t recmasterrole
= 0;
4817 usage("setrecmasterrole");
4820 if (strcmp(argv
[0], "on") == 0) {
4822 } else if (strcmp(argv
[0], "off") == 0) {
4825 usage("setrecmasterrole");
4828 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4829 ctdb
->cmd_pnn
, TIMEOUT(),
4838 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4839 struct ctdb_context
*ctdb
,
4840 int argc
, const char **argv
)
4847 usage("setdbreadonly");
4850 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4854 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4855 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4859 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4860 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4868 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4869 int argc
, const char **argv
)
4876 usage("setdbsticky");
4879 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4883 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4884 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
4888 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4889 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4897 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4898 int argc
, const char **argv
)
4900 const char *db_name
;
4901 struct ctdb_db_context
*db
;
4902 struct ctdb_transaction_handle
*h
;
4907 if (argc
< 2 || argc
> 3) {
4911 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4916 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4917 fprintf(stderr
, "Transactions not supported on DB %s\n",
4922 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4925 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4929 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4931 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4935 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4936 TIMEOUT(), db
, true, &h
);
4938 fprintf(stderr
, "Failed to start transaction on db %s\n",
4943 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
4945 fprintf(stderr
, "Failed to read record for key %s\n",
4947 ctdb_transaction_cancel(h
);
4951 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
4953 ctdb_transaction_cancel(h
);
4957 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4958 int argc
, const char **argv
)
4960 const char *db_name
;
4961 struct ctdb_db_context
*db
;
4962 struct ctdb_transaction_handle
*h
;
4971 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
4976 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
4977 fprintf(stderr
, "Transactions not supported on DB %s\n",
4982 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4985 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4989 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
4991 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
4995 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
4997 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5001 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5002 TIMEOUT(), db
, false, &h
);
5004 fprintf(stderr
, "Failed to start transaction on db %s\n",
5009 ret
= ctdb_transaction_store_record(h
, key
, data
);
5011 fprintf(stderr
, "Failed to store record for key %s\n",
5013 ctdb_transaction_cancel(h
);
5017 ret
= ctdb_transaction_commit(h
);
5019 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5021 ctdb_transaction_cancel(h
);
5028 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5029 int argc
, const char **argv
)
5031 const char *db_name
;
5032 struct ctdb_db_context
*db
;
5033 struct ctdb_transaction_handle
*h
;
5042 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5047 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5048 fprintf(stderr
, "Transactions not supported on DB %s\n",
5053 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5056 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5060 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5062 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5066 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5067 TIMEOUT(), db
, false, &h
);
5069 fprintf(stderr
, "Failed to start transaction on db %s\n",
5074 ret
= ctdb_transaction_delete_record(h
, key
);
5076 fprintf(stderr
, "Failed to delete record for key %s\n",
5078 ctdb_transaction_cancel(h
);
5082 ret
= ctdb_transaction_commit(h
);
5084 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5086 ctdb_transaction_cancel(h
);
5093 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5101 /* Skip whitespace */
5102 n
= strspn(*ptr
, " \t");
5106 /* Quoted ASCII string - no wide characters! */
5108 n
= strcspn(t
, "\"");
5111 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5118 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5122 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5129 #define MAX_LINE_SIZE 1024
5131 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5132 TDB_DATA
*key
, TDB_DATA
*value
)
5134 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5138 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5144 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5145 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5146 /* Line Ignored but not EOF */
5152 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5154 /* Line Ignored but not EOF */
5155 talloc_free(key
->dptr
);
5163 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5164 int argc
, const char **argv
)
5166 const char *db_name
;
5167 struct ctdb_db_context
*db
;
5168 struct ctdb_transaction_handle
*h
;
5171 TDB_DATA key
, value
;
5174 if (argc
< 1 || argc
> 2) {
5178 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5183 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5184 fprintf(stderr
, "Transactions not supported on DB %s\n",
5190 file
= fopen(argv
[1], "r");
5192 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5199 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5202 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5206 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5207 TIMEOUT(), db
, false, &h
);
5209 fprintf(stderr
, "Failed to start transaction on db %s\n",
5214 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5215 if (key
.dsize
!= 0) {
5216 ret
= ctdb_transaction_store_record(h
, key
, value
);
5218 fprintf(stderr
, "Failed to store record\n");
5219 ctdb_transaction_cancel(h
);
5222 talloc_free(key
.dptr
);
5223 talloc_free(value
.dptr
);
5227 ret
= ctdb_transaction_commit(h
);
5229 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5231 ctdb_transaction_cancel(h
);
5235 if (file
!= stdin
) {
5241 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5242 int argc
, const char **argv
)
5244 struct tdb_context
*tdb
;
5246 struct ctdb_ltdb_header header
;
5249 if (argc
< 2 || argc
> 3) {
5253 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5255 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5259 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5261 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5266 data
= tdb_fetch(tdb
, key
);
5267 if (data
.dptr
== NULL
) {
5268 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5273 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5274 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5285 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5287 fprintf(stderr
, "Failed to open output file %s\n",
5292 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5293 if (nwritten
!= data
.dsize
) {
5294 fprintf(stderr
, "Failed to write record to file\n");
5303 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5305 fprintf(stderr
, "Failed to parse header from data\n");
5309 dump_ltdb_header(&header
);
5310 dump_tdb_data("data", data
);
5315 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5316 int argc
, const char **argv
)
5318 struct tdb_context
*tdb
;
5319 TDB_DATA key
, data
[2], value
;
5320 struct ctdb_ltdb_header header
;
5321 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5324 if (argc
< 3 || argc
> 5) {
5328 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5330 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5334 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5336 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5341 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5343 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5348 ZERO_STRUCT(header
);
5351 header
.rsn
= (uint64_t)strtoull(argv
[3], NULL
, 0);
5354 header
.dmaster
= (uint32_t)atol(argv
[4]);
5357 header
.flags
= (uint32_t)atol(argv
[5]);
5360 ctdb_ltdb_header_push(&header
, header_buf
);
5362 data
[0].dsize
= ctdb_ltdb_header_len(&header
);
5363 data
[0].dptr
= header_buf
;
5365 data
[1].dsize
= value
.dsize
;
5366 data
[1].dptr
= value
.dptr
;
5368 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5370 fprintf(stderr
, "Failed to write record %s to file %s\n",
5379 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5380 int argc
, const char **argv
)
5382 const char *db_name
;
5383 struct ctdb_db_context
*db
;
5384 struct ctdb_record_handle
*h
;
5387 bool readonly
= false;
5390 if (argc
< 2 || argc
> 3) {
5395 if (strcmp(argv
[2], "readonly") == 0) {
5402 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5406 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5407 fprintf(stderr
, "DB %s is not a volatile database\n",
5412 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5415 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5419 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5421 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5425 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5426 db
, key
, readonly
, &h
, NULL
, &data
);
5428 fprintf(stderr
, "Failed to read record for key %s\n",
5431 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5432 (int)data
.dsize
, data
.dptr
);
5439 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5440 int argc
, const char **argv
)
5442 const char *db_name
;
5443 struct ctdb_db_context
*db
;
5444 struct ctdb_record_handle
*h
;
5453 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5457 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5458 fprintf(stderr
, "DB %s is not a volatile database\n",
5463 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5466 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5470 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5472 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5476 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5478 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5482 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5483 db
, key
, false, &h
, NULL
, NULL
);
5485 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5489 ret
= ctdb_store_record(h
, data
);
5491 fprintf(stderr
, "Failed to store record for key %s\n",
5499 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5500 int argc
, const char **argv
)
5502 const char *db_name
;
5503 struct ctdb_db_context
*db
;
5504 struct ctdb_record_handle
*h
;
5513 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5517 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5518 fprintf(stderr
, "DB %s is not a volatile database\n",
5523 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5526 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5530 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5532 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5536 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5537 db
, key
, false, &h
, NULL
, &data
);
5539 fprintf(stderr
, "Failed to fetch record for key %s\n",
5544 ret
= ctdb_delete_record(h
);
5546 fprintf(stderr
, "Failed to delete record for key %s\n",
5554 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5555 int argc
, const char **argv
)
5557 struct sockaddr_in sin
;
5563 usage("chktcpport");
5566 port
= atoi(argv
[0]);
5568 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5570 fprintf(stderr
, "Failed to open local socket\n");
5574 v
= fcntl(s
, F_GETFL
, 0);
5575 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5576 fprintf(stderr
, "Unable to set socket non-blocking\n");
5581 bzero(&sin
, sizeof(sin
));
5582 sin
.sin_family
= AF_INET
;
5583 sin
.sin_port
= htons(port
);
5584 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5587 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5594 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5595 int argc
, const char **argv
)
5598 const char *db_name
;
5603 usage("getdbseqnum");
5606 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5610 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5611 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5614 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5619 printf("0x%"PRIx64
"\n", seqnum
);
5623 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5624 int argc
, const char **argv
)
5626 const char *nodestring
= NULL
;
5627 struct ctdb_node_map
*nodemap
;
5629 bool print_hdr
= false;
5632 usage("nodestatus");
5636 nodestring
= argv
[0];
5637 if (strcmp(nodestring
, "all") == 0) {
5642 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap
)) {
5646 if (options
.machinereadable
) {
5647 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5649 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5653 for (i
=0; i
<nodemap
->num
; i
++) {
5654 ret
|= nodemap
->node
[i
].flags
;
5663 } db_stats_fields
[] = {
5664 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5665 DBSTATISTICS_FIELD(db_ro_delegations
),
5666 DBSTATISTICS_FIELD(db_ro_revokes
),
5667 DBSTATISTICS_FIELD(locks
.num_calls
),
5668 DBSTATISTICS_FIELD(locks
.num_current
),
5669 DBSTATISTICS_FIELD(locks
.num_pending
),
5670 DBSTATISTICS_FIELD(locks
.num_failed
),
5671 DBSTATISTICS_FIELD(db_ro_delegations
),
5674 static void print_dbstatistics(const char *db_name
,
5675 struct ctdb_db_statistics
*s
)
5678 const char *prefix
= NULL
;
5681 printf("DB Statistics %s\n", db_name
);
5683 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5684 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5685 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5687 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5688 prefix
= db_stats_fields
[i
].name
;
5689 printf(" %*.*s\n", preflen
-1, preflen
-1,
5690 db_stats_fields
[i
].name
);
5695 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5696 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5697 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5700 printf(" hop_count_buckets:");
5701 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5702 printf(" %d", s
->hop_count_bucket
[i
]);
5706 printf(" lock_buckets:");
5707 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5708 printf(" %d", s
->locks
.buckets
[i
]);
5712 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5713 "locks_latency MIN/AVG/MAX",
5714 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5715 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5717 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5718 "vacuum_latency MIN/AVG/MAX",
5719 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5720 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5722 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5723 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5725 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5726 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5727 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5733 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5734 int argc
, const char **argv
)
5737 const char *db_name
;
5738 struct ctdb_db_statistics
*dbstats
;
5742 usage("dbstatistics");
5745 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5749 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5750 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5753 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5758 print_dbstatistics(db_name
, dbstats
);
5762 struct disable_takeover_runs_state
{
5770 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5773 struct disable_takeover_runs_state
*state
=
5774 (struct disable_takeover_runs_state
*)private_data
;
5777 if (data
.dsize
!= sizeof(int)) {
5782 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5783 ret
= *(int *)data
.dptr
;
5785 state
->status
= ret
;
5789 for (i
=0; i
<state
->node_count
; i
++) {
5790 if (state
->pnn_list
[i
] == ret
) {
5791 state
->reply
[i
] = true;
5797 for (i
=0; i
<state
->node_count
; i
++) {
5798 if (! state
->reply
[i
]) {
5799 state
->done
= false;
5805 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5806 struct ctdb_context
*ctdb
, uint32_t timeout
,
5807 uint32_t *pnn_list
, int count
)
5809 struct ctdb_disable_message disable
= { 0 };
5810 struct disable_takeover_runs_state state
;
5813 disable
.pnn
= ctdb
->pnn
;
5814 disable
.srvid
= next_srvid(ctdb
);
5815 disable
.timeout
= timeout
;
5817 state
.pnn_list
= pnn_list
;
5818 state
.node_count
= count
;
5821 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5822 if (state
.reply
== NULL
) {
5826 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5828 disable_takeover_run_handler
,
5834 for (i
=0; i
<count
; i
++) {
5835 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5844 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5846 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5848 ret
= (state
.status
>= 0 ? 0 : 1);
5852 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5853 disable
.srvid
, &state
);
5857 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5858 int argc
, const char **argv
)
5860 const char *nodestring
= NULL
;
5861 struct ctdb_node_map
*nodemap
, *nodemap2
;
5862 struct ctdb_req_control request
;
5863 uint32_t *pnn_list
, *pnn_list2
;
5864 int ret
, count
, count2
;
5871 nodestring
= argv
[0];
5874 nodemap
= get_nodemap(ctdb
, false);
5875 if (nodemap
== NULL
) {
5879 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
5883 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
5884 mem_ctx
, &pnn_list
);
5886 fprintf(stderr
, "Memory allocation error\n");
5890 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
5891 mem_ctx
, &pnn_list2
);
5893 fprintf(stderr
, "Memory allocation error\n");
5897 /* Disable takeover runs on all connected nodes. A reply
5898 * indicating success is needed from each node so all nodes
5899 * will need to be active.
5901 * A check could be added to not allow reloading of IPs when
5902 * there are disconnected nodes. However, this should
5903 * probably be left up to the administrator.
5905 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
5908 fprintf(stderr
, "Failed to disable takeover runs\n");
5912 /* Now tell all the desired nodes to reload their public IPs.
5913 * Keep trying this until it succeeds. This assumes all
5914 * failures are transient, which might not be true...
5916 ctdb_req_control_reload_public_ips(&request
);
5917 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5918 pnn_list2
, count2
, TIMEOUT(),
5919 &request
, NULL
, NULL
);
5921 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
5924 /* It isn't strictly necessary to wait until takeover runs are
5925 * re-enabled but doing so can't hurt.
5927 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
5929 fprintf(stderr
, "Failed to enable takeover runs\n");
5933 return ipreallocate(mem_ctx
, ctdb
);
5936 static int control_ipiface(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5937 int argc
, const char **argv
)
5939 ctdb_sock_addr addr
;
5946 if (! parse_ip(argv
[0], NULL
, 0, &addr
)) {
5947 fprintf(stderr
, "Failed to Parse IP %s\n", argv
[0]);
5951 iface
= ctdb_sys_find_ifname(&addr
);
5952 if (iface
== NULL
) {
5953 fprintf(stderr
, "Failed to find interface for IP %s\n",
5963 static const struct ctdb_cmd
{
5965 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
5966 bool without_daemon
; /* can be run without daemon running ? */
5967 bool remote
; /* can be run on remote nodes */
5970 } ctdb_commands
[] = {
5971 { "version", control_version
, true, false,
5972 "show version of ctdb", NULL
},
5973 { "status", control_status
, false, true,
5974 "show node status", NULL
},
5975 { "uptime", control_uptime
, false, true,
5976 "show node uptime", NULL
},
5977 { "ping", control_ping
, false, true,
5978 "ping all nodes", NULL
},
5979 { "runstate", control_runstate
, false, true,
5980 "get/check runstate of a node",
5981 "[setup|first_recovery|startup|running]" },
5982 { "getvar", control_getvar
, false, true,
5983 "get a tunable variable", "<name>" },
5984 { "setvar", control_setvar
, false, true,
5985 "set a tunable variable", "<name> <value>" },
5986 { "listvars", control_listvars
, false, true,
5987 "list tunable variables", NULL
},
5988 { "statistics", control_statistics
, false, true,
5989 "show ctdb statistics", NULL
},
5990 { "statisticsreset", control_statistics_reset
, false, true,
5991 "reset ctdb statistics", NULL
},
5992 { "stats", control_stats
, false, true,
5993 "show rolling statistics", "[count]" },
5994 { "ip", control_ip
, false, true,
5995 "show public ips", "[all]" },
5996 { "ipinfo", control_ipinfo
, false, true,
5997 "show public ip details", "<ip>" },
5998 { "ifaces", control_ifaces
, false, true,
5999 "show interfaces", NULL
},
6000 { "setifacelink", control_setifacelink
, false, true,
6001 "set interface link status", "<iface> up|down" },
6002 { "process-exists", control_process_exists
, false, true,
6003 "check if a process exists on a node", "<pid>" },
6004 { "getdbmap", control_getdbmap
, false, true,
6005 "show attached databases", NULL
},
6006 { "getdbstatus", control_getdbstatus
, false, true,
6007 "show database status", "<dbname|dbid>" },
6008 { "catdb", control_catdb
, false, false,
6009 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6010 { "cattdb", control_cattdb
, false, false,
6011 "dump local ctdb database", "<dbname|dbid>" },
6012 { "getmonmode", control_getmonmode
, false, true,
6013 "show monitoring mode", NULL
},
6014 { "getcapabilities", control_getcapabilities
, false, true,
6015 "show node capabilities", NULL
},
6016 { "pnn", control_pnn
, false, false,
6017 "show the pnn of the currnet node", NULL
},
6018 { "lvs", control_lvs
, false, false,
6019 "show lvs configuration", "master|list|status" },
6020 { "disablemonitor", control_disable_monitor
, false, true,
6021 "disable monitoring", NULL
},
6022 { "enablemonitor", control_enable_monitor
, false, true,
6023 "enable monitoring", NULL
},
6024 { "setdebug", control_setdebug
, false, true,
6025 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6026 { "getdebug", control_getdebug
, false, true,
6027 "get debug level", NULL
},
6028 { "attach", control_attach
, false, false,
6029 "attach a database", "<dbname> [persistent|replicated]" },
6030 { "detach", control_detach
, false, false,
6031 "detach database(s)", "<dbname|dbid> ..." },
6032 { "dumpmemory", control_dumpmemory
, false, true,
6033 "dump ctdbd memory map", NULL
},
6034 { "rddumpmemory", control_rddumpmemory
, false, true,
6035 "dump recoverd memory map", NULL
},
6036 { "getpid", control_getpid
, false, true,
6037 "get ctdbd process ID", NULL
},
6038 { "disable", control_disable
, false, true,
6039 "disable a node", NULL
},
6040 { "enable", control_enable
, false, true,
6041 "enable a node", NULL
},
6042 { "stop", control_stop
, false, true,
6043 "stop a node", NULL
},
6044 { "continue", control_continue
, false, true,
6045 "continue a stopped node", NULL
},
6046 { "ban", control_ban
, false, true,
6047 "ban a node", "<bantime>"},
6048 { "unban", control_unban
, false, true,
6049 "unban a node", NULL
},
6050 { "shutdown", control_shutdown
, false, true,
6051 "shutdown ctdb daemon", NULL
},
6052 { "recover", control_recover
, false, true,
6053 "force recovery", NULL
},
6054 { "sync", control_ipreallocate
, false, true,
6055 "run ip reallocation (deprecated)", NULL
},
6056 { "ipreallocate", control_ipreallocate
, false, true,
6057 "run ip reallocation", NULL
},
6058 { "isnotrecmaster", control_isnotrecmaster
, false, false,
6059 "check if local node is the recmaster", NULL
},
6060 { "gratarp", control_gratarp
, false, true,
6061 "send a gratuitous arp", "<ip> <interface>" },
6062 { "tickle", control_tickle
, true, false,
6063 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6064 { "gettickles", control_gettickles
, false, true,
6065 "get the list of tickles", "<ip> [<port>]" },
6066 { "addtickle", control_addtickle
, false, true,
6067 "add a tickle", "<ip>:<port> <ip>:<port>" },
6068 { "deltickle", control_deltickle
, false, true,
6069 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6070 { "check_srvids", control_check_srvids
, false, true,
6071 "check if srvid is registered", "<id> [<id> ...]" },
6072 { "listnodes", control_listnodes
, true, true,
6073 "list nodes in the cluster", NULL
},
6074 { "reloadnodes", control_reloadnodes
, false, false,
6075 "reload the nodes file all nodes", NULL
},
6076 { "moveip", control_moveip
, false, false,
6077 "move an ip address to another node", "<ip> <node>" },
6078 { "addip", control_addip
, false, true,
6079 "add an ip address to a node", "<ip/mask> <iface>" },
6080 { "delip", control_delip
, false, true,
6081 "delete an ip address from a node", "<ip>" },
6082 { "backupdb", control_backupdb
, false, false,
6083 "backup a database into a file", "<dbname|dbid> <file>" },
6084 { "restoredb", control_restoredb
, false, false,
6085 "restore a database from a file", "<file> [dbname]" },
6086 { "dumpdbbackup", control_dumpdbbackup
, true, false,
6087 "dump database from a backup file", "<file>" },
6088 { "wipedb", control_wipedb
, false, false,
6089 "wipe the contents of a database.", "<dbname|dbid>"},
6090 { "recmaster", control_recmaster
, false, true,
6091 "show the pnn for the recovery master", NULL
},
6092 { "event", control_event
, true, false,
6093 "event and event script commands", NULL
},
6094 { "scriptstatus", control_scriptstatus
, true, false,
6095 "show event script status",
6096 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6097 { "natgw", control_natgw
, false, false,
6098 "show natgw configuration", "master|list|status" },
6099 { "natgwlist", control_natgwlist
, false, false,
6100 "show the nodes belonging to this natgw configuration", NULL
},
6101 { "getreclock", control_getreclock
, false, true,
6102 "get recovery lock file", NULL
},
6103 { "setlmasterrole", control_setlmasterrole
, false, true,
6104 "set LMASTER role", "on|off" },
6105 { "setrecmasterrole", control_setrecmasterrole
, false, true,
6106 "set RECMASTER role", "on|off"},
6107 { "setdbreadonly", control_setdbreadonly
, false, true,
6108 "enable readonly records", "<dbname|dbid>" },
6109 { "setdbsticky", control_setdbsticky
, false, true,
6110 "enable sticky records", "<dbname|dbid>"},
6111 { "pfetch", control_pfetch
, false, false,
6112 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6113 { "pstore", control_pstore
, false, false,
6114 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6115 { "pdelete", control_pdelete
, false, false,
6116 "delete record from persistent database", "<dbname|dbid> <key>" },
6117 { "ptrans", control_ptrans
, false, false,
6118 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6119 { "tfetch", control_tfetch
, false, true,
6120 "fetch a record", "<tdb-file> <key> [<file>]" },
6121 { "tstore", control_tstore
, false, true,
6122 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6123 { "readkey", control_readkey
, false, false,
6124 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6125 { "writekey", control_writekey
, false, false,
6126 "write value for a database key", "<dbname|dbid> <key> <value>" },
6127 { "deletekey", control_deletekey
, false, false,
6128 "delete a database key", "<dbname|dbid> <key>" },
6129 { "checktcpport", control_checktcpport
, true, false,
6130 "check if a service is bound to a specific tcp port or not", "<port>" },
6131 { "getdbseqnum", control_getdbseqnum
, false, false,
6132 "get database sequence number", "<dbname|dbid>" },
6133 { "nodestatus", control_nodestatus
, false, true,
6134 "show and return node status", "[all|<pnn-list>]" },
6135 { "dbstatistics", control_dbstatistics
, false, true,
6136 "show database statistics", "<dbname|dbid>" },
6137 { "reloadips", control_reloadips
, false, false,
6138 "reload the public addresses file", "[all|<pnn-list>]" },
6139 { "ipiface", control_ipiface
, true, false,
6140 "Find the interface an ip address is hosted on", "<ip>" },
6143 static const struct ctdb_cmd
*match_command(const char *command
)
6145 const struct ctdb_cmd
*cmd
;
6148 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6149 cmd
= &ctdb_commands
[i
];
6150 if (strlen(command
) == strlen(cmd
->name
) &&
6151 strncmp(command
, cmd
->name
, strlen(command
)) == 0) {
6161 * Show usage message
6163 static void usage_full(void)
6167 poptPrintHelp(pc
, stdout
, 0);
6168 printf("\nCommands:\n");
6169 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6170 printf(" %-15s %-27s %s\n",
6171 ctdb_commands
[i
].name
,
6172 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6173 ctdb_commands
[i
].msg
);
6177 static void usage(const char *command
)
6179 const struct ctdb_cmd
*cmd
;
6181 if (command
== NULL
) {
6186 cmd
= match_command(command
);
6190 poptPrintUsage(pc
, stdout
, 0);
6191 printf("\nCommands:\n");
6192 printf(" %-15s %-27s %s\n",
6193 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6199 struct poptOption cmdline_options
[] = {
6201 { "socket", 's', POPT_ARG_STRING
, &options
.socket
, 0,
6202 "CTDB socket path", "filename" },
6203 { "debug", 'd', POPT_ARG_STRING
, &options
.debuglevelstr
, 0,
6205 { "timelimit", 't', POPT_ARG_INT
, &options
.timelimit
, 0,
6206 "timelimit (in seconds)" },
6207 { "node", 'n', POPT_ARG_INT
, &options
.pnn
, 0,
6208 "node specification - integer" },
6209 { NULL
, 'Y', POPT_ARG_NONE
, &options
.machinereadable
, 0,
6210 "enable machine readable output", NULL
},
6211 { "separator", 'x', POPT_ARG_STRING
, &options
.sep
, 0,
6212 "specify separator for machine readable output", "CHAR" },
6213 { NULL
, 'X', POPT_ARG_NONE
, &options
.machineparsable
, 0,
6214 "enable machine parsable output with separator |", NULL
},
6215 { "verbose", 'v', POPT_ARG_NONE
, &options
.verbose
, 0,
6216 "enable verbose output", NULL
},
6217 { "maxruntime", 'T', POPT_ARG_INT
, &options
.maxruntime
, 0,
6218 "die if runtime exceeds this limit (in seconds)" },
6222 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6225 TALLOC_CTX
*tmp_ctx
;
6226 struct ctdb_context
*ctdb
;
6229 uint64_t srvid_offset
;
6231 tmp_ctx
= talloc_new(NULL
);
6232 if (tmp_ctx
== NULL
) {
6233 fprintf(stderr
, "Memory allocation error\n");
6237 if (cmd
->without_daemon
) {
6238 if (options
.pnn
!= -1) {
6240 "Cannot specify node for command %s\n",
6245 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6246 talloc_free(tmp_ctx
);
6250 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6252 fprintf(stderr
, "Memory allocation error\n");
6256 ctdb
->ev
= tevent_context_init(ctdb
);
6257 if (ctdb
->ev
== NULL
) {
6258 fprintf(stderr
, "Failed to initialize tevent\n");
6262 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, options
.socket
, &ctdb
->client
);
6264 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6267 if (!find_node_xpnn(ctdb
, NULL
)) {
6268 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6273 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6274 srvid_offset
= getpid() & 0xFFFF;
6275 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6277 if (options
.pnn
!= -1) {
6278 status
= verify_pnn(ctdb
, options
.pnn
);
6283 ctdb
->cmd_pnn
= options
.pnn
;
6285 ctdb
->cmd_pnn
= ctdb
->pnn
;
6288 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6289 fprintf(stderr
, "Node cannot be specified for command %s\n",
6294 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6295 talloc_free(tmp_ctx
);
6299 talloc_free(tmp_ctx
);
6303 static void signal_handler(int sig
)
6305 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6308 static void alarm_handler(int sig
)
6310 /* Kill any child processes */
6311 signal(SIGTERM
, signal_handler
);
6317 int main(int argc
, const char *argv
[])
6320 const char **extra_argv
;
6322 const struct ctdb_cmd
*cmd
;
6323 const char *ctdb_socket
;
6329 /* Set default options */
6330 options
.socket
= CTDB_SOCKET
;
6331 options
.debuglevelstr
= NULL
;
6332 options
.timelimit
= 10;
6334 options
.maxruntime
= 0;
6337 ctdb_socket
= getenv("CTDB_SOCKET");
6338 if (ctdb_socket
!= NULL
) {
6339 options
.socket
= ctdb_socket
;
6342 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6343 POPT_CONTEXT_KEEP_FIRST
);
6344 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6345 fprintf(stderr
, "Invalid option %s: %s\n",
6346 poptBadOption(pc
, 0), poptStrerror(opt
));
6350 if (options
.maxruntime
== 0) {
6351 const char *ctdb_timeout
;
6353 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6354 if (ctdb_timeout
!= NULL
) {
6355 options
.maxruntime
= strtoul(ctdb_timeout
, NULL
, 0);
6357 options
.maxruntime
= 120;
6360 if (options
.maxruntime
<= 120) {
6361 /* default timeout is 120 seconds */
6362 options
.maxruntime
= 120;
6365 if (options
.machineparsable
) {
6366 options
.machinereadable
= 1;
6369 /* setup the remaining options for the commands */
6371 extra_argv
= poptGetArgs(pc
);
6374 while (extra_argv
[extra_argc
]) extra_argc
++;
6377 if (extra_argc
< 1) {
6381 cmd
= match_command(extra_argv
[0]);
6383 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6387 /* Enable logging */
6388 setup_logging("ctdb", DEBUG_STDERR
);
6389 if (debug_level_parse(options
.debuglevelstr
, &loglevel
)) {
6390 DEBUGLEVEL
= loglevel
;
6392 DEBUGLEVEL
= DEBUG_ERR
;
6395 signal(SIGALRM
, alarm_handler
);
6396 alarm(options
.maxruntime
);
6398 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6403 (void)poptFreeContext(pc
);