4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/dir.h"
34 #include "lib/util/debug.h"
35 #include "lib/util/samba_util.h"
36 #include "lib/util/util_file.h"
37 #include "lib/util/sys_rw.h"
38 #include "lib/util/smb_strtox.h"
40 #include "common/db_hash.h"
41 #include "common/logging.h"
42 #include "common/path.h"
43 #include "protocol/protocol.h"
44 #include "protocol/protocol_basic.h"
45 #include "protocol/protocol_api.h"
46 #include "protocol/protocol_util.h"
47 #include "common/system_socket.h"
48 #include "client/client.h"
49 #include "client/client_sync.h"
51 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
53 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
54 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
56 #define NODE_FLAGS_UNKNOWN 0x00000040
59 const char *debuglevelstr
;
67 int printemptyrecords
;
74 static poptContext pc
;
77 struct tevent_context
*ev
;
78 struct ctdb_client_context
*client
;
79 struct ctdb_node_map
*nodemap
;
80 uint32_t pnn
, cmd_pnn
, leader_pnn
;
84 static void usage(const char *command
);
86 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
87 struct ctdb_context
*ctdb
,
91 static int send_ipreallocated_control_to_nodes(TALLOC_CTX
*mem_ctx
,
92 struct ctdb_context
*ctdb
,
100 static double timeval_delta(struct timeval
*tv2
, struct timeval
*tv
)
102 return (tv2
->tv_sec
- tv
->tv_sec
) +
103 (tv2
->tv_usec
- tv
->tv_usec
) * 1.0e-6;
106 static struct ctdb_node_and_flags
*get_node_by_pnn(
107 struct ctdb_node_map
*nodemap
,
112 for (i
=0; i
<nodemap
->num
; i
++) {
113 if (nodemap
->node
[i
].pnn
== pnn
) {
114 return &nodemap
->node
[i
];
120 static const char *pretty_print_flags(TALLOC_CTX
*mem_ctx
, uint32_t flags
)
122 static const struct {
126 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
127 { NODE_FLAGS_UNKNOWN
, "UNKNOWN" },
128 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
129 { NODE_FLAGS_BANNED
, "BANNED" },
130 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
131 { NODE_FLAGS_DELETED
, "DELETED" },
132 { NODE_FLAGS_STOPPED
, "STOPPED" },
133 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
135 char *flags_str
= NULL
;
138 for (i
=0; i
<ARRAY_SIZE(flag_names
); i
++) {
139 if (flags
& flag_names
[i
].flag
) {
140 if (flags_str
== NULL
) {
141 flags_str
= talloc_asprintf(mem_ctx
,
142 "%s", flag_names
[i
].name
);
144 flags_str
= talloc_asprintf_append(flags_str
,
145 "|%s", flag_names
[i
].name
);
147 if (flags_str
== NULL
) {
148 return "OUT-OF-MEMORY";
152 if (flags_str
== NULL
) {
159 static uint64_t next_srvid(struct ctdb_context
*ctdb
)
166 * Get consistent nodemap information.
168 * If nodemap is already cached, use that. If not get it.
169 * If the current node is BANNED, then get nodemap from "better" node.
171 static struct ctdb_node_map
*get_nodemap(struct ctdb_context
*ctdb
, bool force
)
174 struct ctdb_node_map
*nodemap
;
175 struct ctdb_node_and_flags
*node
;
176 uint32_t current_node
;
180 TALLOC_FREE(ctdb
->nodemap
);
183 if (ctdb
->nodemap
!= NULL
) {
184 return ctdb
->nodemap
;
187 tmp_ctx
= talloc_new(ctdb
);
188 if (tmp_ctx
== NULL
) {
192 current_node
= ctdb
->pnn
;
194 ret
= ctdb_ctrl_get_nodemap(tmp_ctx
, ctdb
->ev
, ctdb
->client
,
195 current_node
, TIMEOUT(), &nodemap
);
197 fprintf(stderr
, "Failed to get nodemap from node %u\n",
202 node
= get_node_by_pnn(nodemap
, current_node
);
203 if (node
->flags
& NODE_FLAGS_BANNED
) {
206 current_node
= (current_node
+ 1) % nodemap
->num
;
207 node
= get_node_by_pnn(nodemap
, current_node
);
209 (NODE_FLAGS_DELETED
|NODE_FLAGS_DISCONNECTED
))) {
212 } while (current_node
!= ctdb
->pnn
);
214 if (current_node
== ctdb
->pnn
) {
215 /* Tried all nodes in the cluster */
216 fprintf(stderr
, "Warning: All nodes are banned.\n");
223 ctdb
->nodemap
= talloc_steal(ctdb
, nodemap
);
227 talloc_free(tmp_ctx
);
231 static void print_pnn(uint32_t pnn
)
233 if (pnn
== CTDB_UNKNOWN_PNN
) {
241 static bool verify_pnn(struct ctdb_context
*ctdb
, int pnn
)
243 struct ctdb_node_map
*nodemap
;
251 nodemap
= get_nodemap(ctdb
, false);
252 if (nodemap
== NULL
) {
257 for (i
=0; i
<nodemap
->num
; i
++) {
258 if (nodemap
->node
[i
].pnn
== (uint32_t)pnn
) {
264 fprintf(stderr
, "Node %u does not exist\n", pnn
);
268 if (nodemap
->node
[i
].flags
&
269 (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
)) {
270 fprintf(stderr
, "Node %u has status %s\n", pnn
,
271 pretty_print_flags(ctdb
, nodemap
->node
[i
].flags
));
278 static struct ctdb_node_map
*talloc_nodemap(TALLOC_CTX
*mem_ctx
,
279 struct ctdb_node_map
*nodemap
)
281 struct ctdb_node_map
*nodemap2
;
283 nodemap2
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
284 if (nodemap2
== NULL
) {
288 nodemap2
->node
= talloc_array(nodemap2
, struct ctdb_node_and_flags
,
290 if (nodemap2
->node
== NULL
) {
291 talloc_free(nodemap2
);
299 * Get the number and the list of matching nodes
301 * nodestring := NULL | all | pnn,[pnn,...]
303 * If nodestring is NULL, use the current node.
305 static bool parse_nodestring(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
306 const char *nodestring
,
307 struct ctdb_node_map
**out
)
309 struct ctdb_node_map
*nodemap
, *nodemap2
;
310 struct ctdb_node_and_flags
*node
;
313 nodemap
= get_nodemap(ctdb
, false);
314 if (nodemap
== NULL
) {
318 nodemap2
= talloc_nodemap(mem_ctx
, nodemap
);
319 if (nodemap2
== NULL
) {
323 if (nodestring
== NULL
) {
324 for (i
=0; i
<nodemap
->num
; i
++) {
325 if (nodemap
->node
[i
].pnn
== ctdb
->cmd_pnn
) {
326 nodemap2
->node
[0] = nodemap
->node
[i
];
335 if (strcmp(nodestring
, "all") == 0) {
336 for (i
=0; i
<nodemap
->num
; i
++) {
337 nodemap2
->node
[i
] = nodemap
->node
[i
];
339 nodemap2
->num
= nodemap
->num
;
346 ns
= talloc_strdup(mem_ctx
, nodestring
);
351 tok
= strtok(ns
, ",");
352 while (tok
!= NULL
) {
355 pnn
= (uint32_t)smb_strtoul(tok
,
361 fprintf(stderr
, "Invalid node %s\n", tok
);
365 node
= get_node_by_pnn(nodemap
, pnn
);
367 fprintf(stderr
, "Node %u does not exist\n",
372 nodemap2
->node
[nodemap2
->num
] = *node
;
375 tok
= strtok(NULL
, ",");
385 * Remote nodes are initialised as UNHEALTHY in the daemon and their
386 * true status is updated after they are connected. However, there
387 * is a small window when a healthy node may be shown as unhealthy
388 * between connecting and the status update. Hide this for nodes
389 * that are not DISCONNECTED nodes by reporting them as UNKNOWN until
390 * the runstate passes FIRST_RECOVERY. Code paths where this is used
391 * do not make any control decisions depending upon unknown/unhealthy
394 static struct ctdb_node_map
*get_nodemap_unknown(
396 struct ctdb_context
*ctdb
,
397 struct ctdb_node_map
*nodemap_in
)
401 enum ctdb_runstate runstate
;
402 struct ctdb_node_map
*nodemap
;
404 ret
= ctdb_ctrl_get_runstate(mem_ctx
,
411 printf("Unable to get runstate");
415 nodemap
= talloc_nodemap(mem_ctx
, nodemap_in
);
416 if (nodemap
== NULL
) {
417 printf("Unable to get nodemap");
421 nodemap
->num
= nodemap_in
->num
;
422 for (i
=0; i
<nodemap
->num
; i
++) {
423 struct ctdb_node_and_flags
*node_in
= &nodemap_in
->node
[i
];
424 struct ctdb_node_and_flags
*node
= &nodemap
->node
[i
];
428 if (node
->flags
& NODE_FLAGS_DELETED
) {
432 if ((runstate
<= CTDB_RUNSTATE_FIRST_RECOVERY
) &&
433 !(node
->flags
& NODE_FLAGS_DISCONNECTED
) &&
434 (node
->pnn
!= ctdb
->cmd_pnn
)) {
435 node
->flags
= NODE_FLAGS_UNKNOWN
;
442 /* Compare IP address */
443 static bool ctdb_same_ip(ctdb_sock_addr
*ip1
, ctdb_sock_addr
*ip2
)
447 if (ip1
->sa
.sa_family
!= ip2
->sa
.sa_family
) {
451 switch (ip1
->sa
.sa_family
) {
453 ret
= (memcmp(&ip1
->ip
.sin_addr
, &ip2
->ip
.sin_addr
,
454 sizeof(struct in_addr
)) == 0);
458 ret
= (memcmp(&ip1
->ip6
.sin6_addr
, &ip2
->ip6
.sin6_addr
,
459 sizeof(struct in6_addr
)) == 0);
466 /* Append a node to a node map with given address and flags */
467 static bool node_map_add(struct ctdb_node_map
*nodemap
,
468 const char *nstr
, uint32_t flags
)
472 struct ctdb_node_and_flags
*n
;
475 ret
= ctdb_sock_addr_from_string(nstr
, &addr
, false);
477 fprintf(stderr
, "Invalid IP address %s\n", nstr
);
482 nodemap
->node
= talloc_realloc(nodemap
, nodemap
->node
,
483 struct ctdb_node_and_flags
, num
+1);
484 if (nodemap
->node
== NULL
) {
488 n
= &nodemap
->node
[num
];
493 nodemap
->num
= num
+1;
497 /* Read a nodes file into a node map */
498 static struct ctdb_node_map
*ctdb_read_nodes_file(TALLOC_CTX
*mem_ctx
,
504 struct ctdb_node_map
*nodemap
;
506 nodemap
= talloc_zero(mem_ctx
, struct ctdb_node_map
);
507 if (nodemap
== NULL
) {
511 lines
= file_lines_load(nlist
, &nlines
, 0, mem_ctx
);
516 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
520 for (i
=0; i
<nlines
; i
++) {
526 /* strip leading spaces */
527 while((*node
== ' ') || (*node
== '\t')) {
533 /* strip trailing spaces */
535 ((node
[len
-1] == ' ') || (node
[len
-1] == '\t')))
545 /* A "deleted" node is a node that is
546 commented out in the nodes file. This is
547 used instead of removing a line, which
548 would cause subsequent nodes to change
550 flags
= NODE_FLAGS_DELETED
;
551 node
= discard_const("0.0.0.0");
555 if (! node_map_add(nodemap
, node
, flags
)) {
557 TALLOC_FREE(nodemap
);
566 static struct ctdb_node_map
*read_nodes_file(TALLOC_CTX
*mem_ctx
, uint32_t pnn
)
568 struct ctdb_node_map
*nodemap
;
569 const char *nodes_list
= NULL
;
571 const char *basedir
= getenv("CTDB_BASE");
572 if (basedir
== NULL
) {
573 basedir
= CTDB_ETCDIR
;
575 nodes_list
= talloc_asprintf(mem_ctx
, "%s/nodes", basedir
);
576 if (nodes_list
== NULL
) {
577 fprintf(stderr
, "Memory allocation error\n");
581 nodemap
= ctdb_read_nodes_file(mem_ctx
, nodes_list
);
582 if (nodemap
== NULL
) {
583 fprintf(stderr
, "Failed to read nodes file \"%s\"\n",
591 static struct ctdb_dbid
*db_find(TALLOC_CTX
*mem_ctx
,
592 struct ctdb_context
*ctdb
,
593 struct ctdb_dbid_map
*dbmap
,
596 struct ctdb_dbid
*db
= NULL
;
601 for (i
=0; i
<dbmap
->num
; i
++) {
602 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
603 ctdb
->pnn
, TIMEOUT(),
604 dbmap
->dbs
[i
].db_id
, &name
);
609 if (strcmp(db_name
, name
) == 0) {
610 talloc_free(discard_const(name
));
619 static bool db_exists(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
620 const char *db_arg
, uint32_t *db_id
,
621 const char **db_name
, uint8_t *db_flags
)
623 struct ctdb_dbid_map
*dbmap
;
624 struct ctdb_dbid
*db
= NULL
;
626 const char *name
= NULL
;
630 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
631 ctdb
->pnn
, TIMEOUT(), &dbmap
);
636 if (strncmp(db_arg
, "0x", 2) == 0) {
637 id
= smb_strtoul(db_arg
, NULL
, 0, &ret
, SMB_STR_STANDARD
);
641 for (i
=0; i
<dbmap
->num
; i
++) {
642 if (id
== dbmap
->dbs
[i
].db_id
) {
649 db
= db_find(mem_ctx
, ctdb
, dbmap
, name
);
653 fprintf(stderr
, "No database matching '%s' found\n", db_arg
);
658 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
659 ctdb
->pnn
, TIMEOUT(), id
, &name
);
668 if (db_name
!= NULL
) {
669 *db_name
= talloc_strdup(mem_ctx
, name
);
671 if (db_flags
!= NULL
) {
672 *db_flags
= db
->flags
;
677 static int hex_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
684 fprintf(stderr
, "Key (%s) contains odd number of hex digits\n",
689 data
.dsize
= len
/ 2;
690 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
691 if (data
.dptr
== NULL
) {
695 for (i
=0; i
<data
.dsize
; i
++) {
696 bool ok
= hex_byte(&str
[i
*2], &data
.dptr
[i
]);
698 fprintf(stderr
, "Invalid hex: %s\n", &str
[i
*2]);
707 static int str_to_data(const char *str
, size_t len
, TALLOC_CTX
*mem_ctx
,
713 if (strncmp(str
, "0x", 2) == 0) {
714 ret
= hex_to_data(str
+2, len
-2, mem_ctx
, &data
);
719 data
.dptr
= talloc_memdup(mem_ctx
, str
, len
);
720 if (data
.dptr
== NULL
) {
730 static int run_helper(TALLOC_CTX
*mem_ctx
, const char *command
,
731 const char *path
, int argc
, const char **argv
)
734 int save_errno
, status
, ret
;
735 const char **new_argv
;
738 new_argv
= talloc_array(mem_ctx
, const char *, argc
+ 2);
739 if (new_argv
== NULL
) {
744 for (i
=0; i
<argc
; i
++) {
745 new_argv
[i
+1] = argv
[i
];
747 new_argv
[argc
+1] = NULL
;
752 talloc_free(new_argv
);
753 fprintf(stderr
, "Failed to fork %s (%s) - %s\n",
754 command
, path
, strerror(save_errno
));
759 ret
= execv(path
, discard_const(new_argv
));
763 /* Should not happen */
767 talloc_free(new_argv
);
769 ret
= waitpid(pid
, &status
, 0);
772 fprintf(stderr
, "waitpid() failed for %s - %s\n",
773 command
, strerror(save_errno
));
777 if (WIFEXITED(status
)) {
778 int pstatus
= WEXITSTATUS(status
);
779 if (WIFSIGNALED(status
)) {
780 fprintf(stderr
, "%s terminated with signal %d\n",
781 command
, WTERMSIG(status
));
783 } else if (pstatus
>= 64 && pstatus
< 255) {
784 fprintf(stderr
, "%s failed with error %d\n",
785 command
, pstatus
-64);
791 } else if (WIFSIGNALED(status
)) {
792 fprintf(stderr
, "%s terminated with signal %d\n",
793 command
, WTERMSIG(status
));
800 static void leader_handler(uint64_t srvid
,
804 struct ctdb_context
*ctdb
= talloc_get_type_abort(
805 private_data
, struct ctdb_context
);
810 ret
= ctdb_uint32_pull(data
.dptr
, data
.dsize
, &leader_pnn
, &np
);
816 ctdb
->leader_pnn
= leader_pnn
;
819 static bool get_leader_done(void *private_data
)
821 struct ctdb_context
*ctdb
= talloc_get_type_abort(
822 private_data
, struct ctdb_context
);
824 return ctdb
->leader_pnn
!= CTDB_UNKNOWN_PNN
;
827 static int get_leader(TALLOC_CTX
*mem_ctx
,
828 struct ctdb_context
*ctdb
,
833 ret
= ctdb_client_wait_func_timeout(ctdb
->ev
,
838 * If ETIMEDOUT then assume there is no leader and succeed so
839 * initial value of CTDB_UNKNOWN_PNN is returned
841 if (ret
== ETIMEDOUT
) {
843 } else if (ret
!= 0) {
844 fprintf(stderr
, "Error getting leader\n");
848 *leader
= ctdb
->leader_pnn
;
856 static int control_version(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
857 int argc
, const char **argv
)
859 printf("%s\n", SAMBA_VERSION_STRING
);
863 static bool partially_online(TALLOC_CTX
*mem_ctx
,
864 struct ctdb_context
*ctdb
,
865 struct ctdb_node_and_flags
*node
)
867 struct ctdb_iface_list
*iface_list
;
872 if (node
->flags
!= 0) {
876 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
877 node
->pnn
, TIMEOUT(), &iface_list
);
883 for (i
=0; i
< iface_list
->num
; i
++) {
884 if (iface_list
->iface
[i
].link_state
== 0) {
893 static void print_nodemap_machine(TALLOC_CTX
*mem_ctx
,
894 struct ctdb_context
*ctdb
,
895 struct ctdb_node_map
*nodemap
,
898 struct ctdb_node_and_flags
*node
;
901 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
905 "Disconnected", options
.sep
,
906 "Unknown", options
.sep
,
907 "Banned", options
.sep
,
908 "Disabled", options
.sep
,
909 "Unhealthy", options
.sep
,
910 "Stopped", options
.sep
,
911 "Inactive", options
.sep
,
912 "PartiallyOnline", options
.sep
,
913 "ThisNode", options
.sep
);
915 for (i
=0; i
<nodemap
->num
; i
++) {
916 node
= &nodemap
->node
[i
];
917 if (node
->flags
& NODE_FLAGS_DELETED
) {
921 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
923 node
->pnn
, options
.sep
,
924 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
926 !! (node
->flags
& NODE_FLAGS_DISCONNECTED
), options
.sep
,
927 !! (node
->flags
& NODE_FLAGS_UNKNOWN
), options
.sep
,
928 !! (node
->flags
& NODE_FLAGS_BANNED
), options
.sep
,
929 !! (node
->flags
& NODE_FLAGS_PERMANENTLY_DISABLED
),
931 !! (node
->flags
& NODE_FLAGS_UNHEALTHY
), options
.sep
,
932 !! (node
->flags
& NODE_FLAGS_STOPPED
), options
.sep
,
933 !! (node
->flags
& NODE_FLAGS_INACTIVE
), options
.sep
,
934 partially_online(mem_ctx
, ctdb
, node
), options
.sep
,
935 (node
->pnn
== mypnn
)?'Y':'N', options
.sep
);
940 static void print_nodemap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
941 struct ctdb_node_map
*nodemap
, uint32_t mypnn
,
944 struct ctdb_node_and_flags
*node
;
945 int num_deleted_nodes
= 0;
948 for (i
=0; i
<nodemap
->num
; i
++) {
949 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
955 if (num_deleted_nodes
== 0) {
956 printf("Number of nodes:%d\n", nodemap
->num
);
958 printf("Number of nodes:%d "
959 "(including %d deleted nodes)\n",
960 nodemap
->num
, num_deleted_nodes
);
964 for (i
=0; i
<nodemap
->num
; i
++) {
965 node
= &nodemap
->node
[i
];
966 if (node
->flags
& NODE_FLAGS_DELETED
) {
970 printf("pnn:%u %-16s %s%s\n",
972 ctdb_sock_addr_to_string(mem_ctx
, &node
->addr
, false),
973 partially_online(mem_ctx
, ctdb
, node
) ?
975 pretty_print_flags(mem_ctx
, node
->flags
),
976 node
->pnn
== mypnn
? " (THIS NODE)" : "");
980 static void print_status(TALLOC_CTX
*mem_ctx
,
981 struct ctdb_context
*ctdb
,
982 struct ctdb_node_map
*nodemap
,
984 struct ctdb_vnn_map
*vnnmap
,
990 print_nodemap(mem_ctx
, ctdb
, nodemap
, mypnn
, true);
992 if (vnnmap
->generation
== INVALID_GENERATION
) {
993 printf("Generation:INVALID\n");
995 printf("Generation:%u\n", vnnmap
->generation
);
997 printf("Size:%d\n", vnnmap
->size
);
998 for (i
=0; i
<vnnmap
->size
; i
++) {
999 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
1002 printf("Recovery mode:%s (%d)\n",
1003 recmode
== CTDB_RECOVERY_NORMAL
? "NORMAL" : "RECOVERY",
1009 static int control_status(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1010 int argc
, const char **argv
)
1012 struct ctdb_node_map
*nodemap_in
;
1013 struct ctdb_node_map
*nodemap
;
1014 struct ctdb_vnn_map
*vnnmap
;
1023 nodemap_in
= get_nodemap(ctdb
, false);
1024 if (nodemap_in
== NULL
) {
1028 nodemap
= get_nodemap_unknown(mem_ctx
, ctdb
, nodemap_in
);
1029 if (nodemap
== NULL
) {
1033 if (options
.machinereadable
== 1) {
1034 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
1038 ret
= ctdb_ctrl_getvnnmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1039 ctdb
->cmd_pnn
, TIMEOUT(), &vnnmap
);
1044 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1045 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
1050 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
1055 print_status(mem_ctx
,
1065 static int control_uptime(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1066 int argc
, const char **argv
)
1068 struct ctdb_uptime
*uptime
;
1069 int ret
, tmp
, days
, hours
, minutes
, seconds
;
1071 ret
= ctdb_ctrl_uptime(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1072 ctdb
->cmd_pnn
, TIMEOUT(), &uptime
);
1077 printf("Current time of node %-4u : %s",
1078 ctdb
->cmd_pnn
, ctime(&uptime
->current_time
.tv_sec
));
1080 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
1081 seconds
= tmp
% 60; tmp
/= 60;
1082 minutes
= tmp
% 60; tmp
/= 60;
1083 hours
= tmp
% 24; tmp
/= 24;
1086 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
1087 days
, hours
, minutes
, seconds
,
1088 ctime(&uptime
->ctdbd_start_time
.tv_sec
));
1090 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
1091 seconds
= tmp
% 60; tmp
/= 60;
1092 minutes
= tmp
% 60; tmp
/= 60;
1093 hours
= tmp
% 24; tmp
/= 24;
1096 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
1097 days
, hours
, minutes
, seconds
,
1098 ctime(&uptime
->last_recovery_finished
.tv_sec
));
1100 printf("Duration of last recovery/failover: %lf seconds\n",
1101 timeval_delta(&uptime
->last_recovery_finished
,
1102 &uptime
->last_recovery_started
));
1107 static int control_ping(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1108 int argc
, const char **argv
)
1111 int ret
, num_clients
;
1113 tv
= timeval_current();
1114 ret
= ctdb_ctrl_ping(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1115 ctdb
->cmd_pnn
, TIMEOUT(), &num_clients
);
1120 printf("response from %u time=%.6f sec (%d clients)\n",
1121 ctdb
->cmd_pnn
, timeval_elapsed(&tv
), num_clients
);
1125 static int control_runstate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1126 int argc
, const char **argv
)
1128 enum ctdb_runstate runstate
;
1132 ret
= ctdb_ctrl_get_runstate(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1133 ctdb
->cmd_pnn
, TIMEOUT(), &runstate
);
1139 for (i
=0; i
<argc
; i
++) {
1140 enum ctdb_runstate t
;
1143 t
= ctdb_runstate_from_string(argv
[i
]);
1144 if (t
== CTDB_RUNSTATE_UNKNOWN
) {
1145 printf("Invalid run state (%s)\n", argv
[i
]);
1149 if (t
== runstate
) {
1156 printf("CTDB not in required run state (got %s)\n",
1157 ctdb_runstate_to_string(runstate
));
1161 printf("%s\n", ctdb_runstate_to_string(runstate
));
1165 static int control_getvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1166 int argc
, const char **argv
)
1168 struct ctdb_var_list
*tun_var_list
;
1177 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1178 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1181 "Failed to get list of variables from node %u\n",
1187 for (i
=0; i
<tun_var_list
->count
; i
++) {
1188 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1195 printf("No such tunable %s\n", argv
[0]);
1199 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1200 ctdb
->cmd_pnn
, TIMEOUT(), argv
[0], &value
);
1205 printf("%-26s = %u\n", argv
[0], value
);
1209 static int control_setvar(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1210 int argc
, const char **argv
)
1212 struct ctdb_var_list
*tun_var_list
;
1213 struct ctdb_tunable tunable
;
1222 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1223 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1226 "Failed to get list of variables from node %u\n",
1232 for (i
=0; i
<tun_var_list
->count
; i
++) {
1233 if (strcasecmp(tun_var_list
->var
[i
], argv
[0]) == 0) {
1240 printf("No such tunable %s\n", argv
[0]);
1244 tunable
.name
= argv
[0];
1245 tunable
.value
= smb_strtoul(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
1250 ret
= ctdb_ctrl_set_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1251 ctdb
->cmd_pnn
, TIMEOUT(), &tunable
);
1255 "Setting obsolete tunable variable '%s'\n",
1264 static int control_listvars(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1265 int argc
, const char **argv
)
1267 struct ctdb_var_list
*tun_var_list
;
1274 ret
= ctdb_ctrl_list_tunables(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1275 ctdb
->cmd_pnn
, TIMEOUT(), &tun_var_list
);
1280 for (i
=0; i
<tun_var_list
->count
; i
++) {
1281 control_getvar(mem_ctx
, ctdb
, 1, &tun_var_list
->var
[i
]);
1290 } stats_fields
[] = {
1291 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1292 STATISTICS_FIELD(num_clients
),
1293 STATISTICS_FIELD(frozen
),
1294 STATISTICS_FIELD(recovering
),
1295 STATISTICS_FIELD(num_recoveries
),
1296 STATISTICS_FIELD(client_packets_sent
),
1297 STATISTICS_FIELD(client_packets_recv
),
1298 STATISTICS_FIELD(node_packets_sent
),
1299 STATISTICS_FIELD(node_packets_recv
),
1300 STATISTICS_FIELD(keepalive_packets_sent
),
1301 STATISTICS_FIELD(keepalive_packets_recv
),
1302 STATISTICS_FIELD(node
.req_call
),
1303 STATISTICS_FIELD(node
.reply_call
),
1304 STATISTICS_FIELD(node
.req_dmaster
),
1305 STATISTICS_FIELD(node
.reply_dmaster
),
1306 STATISTICS_FIELD(node
.reply_error
),
1307 STATISTICS_FIELD(node
.req_message
),
1308 STATISTICS_FIELD(node
.req_control
),
1309 STATISTICS_FIELD(node
.reply_control
),
1310 STATISTICS_FIELD(node
.req_tunnel
),
1311 STATISTICS_FIELD(client
.req_call
),
1312 STATISTICS_FIELD(client
.req_message
),
1313 STATISTICS_FIELD(client
.req_control
),
1314 STATISTICS_FIELD(client
.req_tunnel
),
1315 STATISTICS_FIELD(timeouts
.call
),
1316 STATISTICS_FIELD(timeouts
.control
),
1317 STATISTICS_FIELD(timeouts
.traverse
),
1318 STATISTICS_FIELD(locks
.num_calls
),
1319 STATISTICS_FIELD(locks
.num_current
),
1320 STATISTICS_FIELD(locks
.num_pending
),
1321 STATISTICS_FIELD(locks
.num_failed
),
1322 STATISTICS_FIELD(total_calls
),
1323 STATISTICS_FIELD(pending_calls
),
1324 STATISTICS_FIELD(childwrite_calls
),
1325 STATISTICS_FIELD(pending_childwrite_calls
),
1326 STATISTICS_FIELD(memory_used
),
1327 STATISTICS_FIELD(max_hop_count
),
1328 STATISTICS_FIELD(total_ro_delegations
),
1329 STATISTICS_FIELD(total_ro_revokes
),
1332 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1334 static void print_statistics_machine(struct ctdb_statistics
*s
,
1340 printf("CTDB version%s", options
.sep
);
1341 printf("Current time of statistics%s", options
.sep
);
1342 printf("Statistics collected since%s", options
.sep
);
1343 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1344 printf("%s%s", stats_fields
[i
].name
, options
.sep
);
1346 printf("num_reclock_ctdbd_latency%s", options
.sep
);
1347 printf("min_reclock_ctdbd_latency%s", options
.sep
);
1348 printf("avg_reclock_ctdbd_latency%s", options
.sep
);
1349 printf("max_reclock_ctdbd_latency%s", options
.sep
);
1351 printf("num_reclock_recd_latency%s", options
.sep
);
1352 printf("min_reclock_recd_latency%s", options
.sep
);
1353 printf("avg_reclock_recd_latency%s", options
.sep
);
1354 printf("max_reclock_recd_latency%s", options
.sep
);
1356 printf("num_call_latency%s", options
.sep
);
1357 printf("min_call_latency%s", options
.sep
);
1358 printf("avg_call_latency%s", options
.sep
);
1359 printf("max_call_latency%s", options
.sep
);
1361 printf("num_lockwait_latency%s", options
.sep
);
1362 printf("min_lockwait_latency%s", options
.sep
);
1363 printf("avg_lockwait_latency%s", options
.sep
);
1364 printf("max_lockwait_latency%s", options
.sep
);
1366 printf("num_childwrite_latency%s", options
.sep
);
1367 printf("min_childwrite_latency%s", options
.sep
);
1368 printf("avg_childwrite_latency%s", options
.sep
);
1369 printf("max_childwrite_latency%s", options
.sep
);
1373 printf("%u%s", CTDB_PROTOCOL
, options
.sep
);
1374 printf("%u%s", (uint32_t)s
->statistics_current_time
.tv_sec
, options
.sep
);
1375 printf("%u%s", (uint32_t)s
->statistics_start_time
.tv_sec
, options
.sep
);
1376 for (i
=0;i
<ARRAY_SIZE(stats_fields
);i
++) {
1378 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
),
1381 printf("%u%s", s
->reclock
.ctdbd
.num
, options
.sep
);
1382 printf("%.6f%s", s
->reclock
.ctdbd
.min
, options
.sep
);
1383 printf("%.6f%s", LATENCY_AVG(s
->reclock
.ctdbd
), options
.sep
);
1384 printf("%.6f%s", s
->reclock
.ctdbd
.max
, options
.sep
);
1386 printf("%u%s", s
->reclock
.recd
.num
, options
.sep
);
1387 printf("%.6f%s", s
->reclock
.recd
.min
, options
.sep
);
1388 printf("%.6f%s", LATENCY_AVG(s
->reclock
.recd
), options
.sep
);
1389 printf("%.6f%s", s
->reclock
.recd
.max
, options
.sep
);
1391 printf("%d%s", s
->call_latency
.num
, options
.sep
);
1392 printf("%.6f%s", s
->call_latency
.min
, options
.sep
);
1393 printf("%.6f%s", LATENCY_AVG(s
->call_latency
), options
.sep
);
1394 printf("%.6f%s", s
->call_latency
.max
, options
.sep
);
1396 printf("%u%s", s
->locks
.latency
.num
, options
.sep
);
1397 printf("%.6f%s", s
->locks
.latency
.min
, options
.sep
);
1398 printf("%.6f%s", LATENCY_AVG(s
->locks
.latency
), options
.sep
);
1399 printf("%.6f%s", s
->locks
.latency
.max
, options
.sep
);
1401 printf("%d%s", s
->childwrite_latency
.num
, options
.sep
);
1402 printf("%.6f%s", s
->childwrite_latency
.min
, options
.sep
);
1403 printf("%.6f%s", LATENCY_AVG(s
->childwrite_latency
), options
.sep
);
1404 printf("%.6f%s", s
->childwrite_latency
.max
, options
.sep
);
1408 static void print_statistics(struct ctdb_statistics
*s
)
1410 int tmp
, days
, hours
, minutes
, seconds
;
1412 const char *prefix
= NULL
;
1415 tmp
= s
->statistics_current_time
.tv_sec
-
1416 s
->statistics_start_time
.tv_sec
;
1417 seconds
= tmp
% 60; tmp
/= 60;
1418 minutes
= tmp
% 60; tmp
/= 60;
1419 hours
= tmp
% 24; tmp
/= 24;
1422 printf("CTDB version %u\n", CTDB_PROTOCOL
);
1423 printf("Current time of statistics : %s",
1424 ctime(&s
->statistics_current_time
.tv_sec
));
1425 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1426 days
, hours
, minutes
, seconds
,
1427 ctime(&s
->statistics_start_time
.tv_sec
));
1429 for (i
=0; i
<ARRAY_SIZE(stats_fields
); i
++) {
1430 if (strchr(stats_fields
[i
].name
, '.') != NULL
) {
1431 preflen
= strcspn(stats_fields
[i
].name
, ".") + 1;
1433 strncmp(prefix
, stats_fields
[i
].name
, preflen
) != 0) {
1434 prefix
= stats_fields
[i
].name
;
1435 printf(" %*.*s\n", preflen
-1, preflen
-1,
1436 stats_fields
[i
].name
);
1441 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
1442 stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
1443 *(uint32_t *)(stats_fields
[i
].offset
+(uint8_t *)s
));
1446 printf(" hop_count_buckets:");
1447 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1448 printf(" %d", s
->hop_count_bucket
[i
]);
1451 printf(" lock_buckets:");
1452 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
1453 printf(" %d", s
->locks
.buckets
[i
]);
1456 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1457 "locks_latency MIN/AVG/MAX",
1458 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
1459 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
1461 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1462 "reclock_ctdbd MIN/AVG/MAX",
1463 s
->reclock
.ctdbd
.min
, LATENCY_AVG(s
->reclock
.ctdbd
),
1464 s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
1466 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1467 "reclock_recd MIN/AVG/MAX",
1468 s
->reclock
.recd
.min
, LATENCY_AVG(s
->reclock
.recd
),
1469 s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
1471 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1472 "call_latency MIN/AVG/MAX",
1473 s
->call_latency
.min
, LATENCY_AVG(s
->call_latency
),
1474 s
->call_latency
.max
, s
->call_latency
.num
);
1476 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1477 "childwrite_latency MIN/AVG/MAX",
1478 s
->childwrite_latency
.min
,
1479 LATENCY_AVG(s
->childwrite_latency
),
1480 s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
1483 static int control_statistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1484 int argc
, const char **argv
)
1486 struct ctdb_statistics
*stats
;
1490 usage("statistics");
1493 ret
= ctdb_ctrl_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1494 ctdb
->cmd_pnn
, TIMEOUT(), &stats
);
1499 if (options
.machinereadable
) {
1500 print_statistics_machine(stats
, true);
1502 print_statistics(stats
);
1508 static int control_statistics_reset(TALLOC_CTX
*mem_ctx
,
1509 struct ctdb_context
*ctdb
,
1510 int argc
, const char **argv
)
1515 usage("statisticsreset");
1518 ret
= ctdb_ctrl_statistics_reset(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1519 ctdb
->cmd_pnn
, TIMEOUT());
1527 static int control_stats(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1528 int argc
, const char **argv
)
1530 struct ctdb_statistics_list
*slist
;
1531 int ret
, count
= 0, i
;
1532 bool show_header
= true;
1539 count
= atoi(argv
[0]);
1542 ret
= ctdb_ctrl_get_stat_history(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1543 ctdb
->cmd_pnn
, TIMEOUT(), &slist
);
1548 for (i
=0; i
<slist
->num
; i
++) {
1549 if (slist
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
1552 if (options
.machinereadable
== 1) {
1553 print_statistics_machine(&slist
->stats
[i
],
1555 show_header
= false;
1557 print_statistics(&slist
->stats
[i
]);
1559 if (count
> 0 && i
== count
) {
1567 static int ctdb_public_ip_cmp(const void *a
, const void *b
)
1569 const struct ctdb_public_ip
*ip_a
= a
;
1570 const struct ctdb_public_ip
*ip_b
= b
;
1572 return ctdb_sock_addr_cmp(&ip_a
->addr
, &ip_b
->addr
);
1575 static void print_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1576 struct ctdb_public_ip_list
*ips
,
1577 struct ctdb_public_ip_info
**ipinfo
,
1581 char *conf
, *avail
, *active
;
1583 if (options
.machinereadable
== 1) {
1584 printf("%s%s%s%s%s", options
.sep
,
1585 "Public IP", options
.sep
,
1586 "Node", options
.sep
);
1587 if (options
.verbose
== 1) {
1588 printf("%s%s%s%s%s%s\n",
1589 "ActiveInterfaces", options
.sep
,
1590 "AvailableInterfaces", options
.sep
,
1591 "ConfiguredInterfaces", options
.sep
);
1597 printf("Public IPs on ALL nodes\n");
1599 printf("Public IPs on node %u\n", ctdb
->cmd_pnn
);
1603 for (i
= 0; i
< ips
->num
; i
++) {
1605 if (options
.machinereadable
== 1) {
1606 printf("%s%s%s%d%s", options
.sep
,
1607 ctdb_sock_addr_to_string(
1608 mem_ctx
, &ips
->ip
[i
].addr
, false),
1610 (int)ips
->ip
[i
].pnn
, options
.sep
);
1612 printf("%s", ctdb_sock_addr_to_string(
1613 mem_ctx
, &ips
->ip
[i
].addr
, false));
1616 if (options
.verbose
== 0) {
1617 if (options
.machinereadable
== 1) {
1620 printf(" %d\n", (int)ips
->ip
[i
].pnn
);
1629 if (ipinfo
[i
] == NULL
) {
1633 for (j
=0; j
<ipinfo
[i
]->ifaces
->num
; j
++) {
1634 struct ctdb_iface
*iface
;
1636 iface
= &ipinfo
[i
]->ifaces
->iface
[j
];
1638 conf
= talloc_strdup(mem_ctx
, iface
->name
);
1640 conf
= talloc_asprintf_append(
1641 conf
, ",%s", iface
->name
);
1644 if (ipinfo
[i
]->active_idx
== j
) {
1645 active
= iface
->name
;
1648 if (iface
->link_state
== 0) {
1652 if (avail
== NULL
) {
1653 avail
= talloc_strdup(mem_ctx
, iface
->name
);
1655 avail
= talloc_asprintf_append(
1656 avail
, ",%s", iface
->name
);
1662 if (options
.machinereadable
== 1) {
1663 printf("%s%s%s%s%s%s\n",
1664 active
? active
: "", options
.sep
,
1665 avail
? avail
: "", options
.sep
,
1666 conf
? conf
: "", options
.sep
);
1668 printf(" node[%d] active[%s] available[%s]"
1669 " configured[%s]\n",
1670 (int)ips
->ip
[i
].pnn
, active
? active
: "",
1671 avail
? avail
: "", conf
? conf
: "");
1676 static int collect_ips(uint8_t *keybuf
, size_t keylen
, uint8_t *databuf
,
1677 size_t datalen
, void *private_data
)
1679 struct ctdb_public_ip_list
*ips
= talloc_get_type_abort(
1680 private_data
, struct ctdb_public_ip_list
);
1681 struct ctdb_public_ip
*ip
;
1683 ip
= (struct ctdb_public_ip
*)databuf
;
1684 ips
->ip
[ips
->num
] = *ip
;
1690 static int get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
1691 struct ctdb_public_ip_list
**out
)
1693 struct ctdb_node_map
*nodemap
;
1694 struct ctdb_public_ip_list
*ips
;
1695 struct db_hash_context
*ipdb
;
1700 nodemap
= get_nodemap(ctdb
, false);
1701 if (nodemap
== NULL
) {
1705 ret
= db_hash_init(mem_ctx
, "ips", 101, DB_HASH_COMPLEX
, &ipdb
);
1710 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
1716 for (i
=0; i
<count
; i
++) {
1717 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1718 pnn_list
[i
], TIMEOUT(),
1724 for (j
=0; j
<ips
->num
; j
++) {
1725 struct ctdb_public_ip ip
;
1727 ip
.pnn
= ips
->ip
[j
].pnn
;
1728 ip
.addr
= ips
->ip
[j
].addr
;
1730 if (pnn_list
[i
] == ip
.pnn
) {
1731 /* Node claims IP is hosted on it, so
1732 * save that information
1734 ret
= db_hash_add(ipdb
, (uint8_t *)&ip
.addr
,
1736 (uint8_t *)&ip
, sizeof(ip
));
1741 /* Node thinks IP is hosted elsewhere,
1742 * so overwrite with CTDB_UNKNOWN_PNN
1743 * if there's no existing entry
1745 ret
= db_hash_exists(ipdb
, (uint8_t *)&ip
.addr
,
1747 if (ret
== ENOENT
) {
1748 ip
.pnn
= CTDB_UNKNOWN_PNN
;
1749 ret
= db_hash_add(ipdb
,
1750 (uint8_t *)&ip
.addr
,
1764 talloc_free(pnn_list
);
1766 ret
= db_hash_traverse(ipdb
, NULL
, NULL
, &count
);
1771 ips
= talloc_zero(mem_ctx
, struct ctdb_public_ip_list
);
1776 ips
->ip
= talloc_array(ips
, struct ctdb_public_ip
, count
);
1777 if (ips
->ip
== NULL
) {
1781 ret
= db_hash_traverse(ipdb
, collect_ips
, ips
, &count
);
1786 if ((unsigned int)count
!= ips
->num
) {
1800 static int control_ip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1801 int argc
, const char **argv
)
1803 struct ctdb_public_ip_list
*ips
;
1804 struct ctdb_public_ip_info
**ipinfo
;
1807 bool do_all
= false;
1814 if (strcmp(argv
[0], "all") == 0) {
1822 ret
= get_all_public_ips(ctdb
, mem_ctx
, &ips
);
1824 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1825 ctdb
->cmd_pnn
, TIMEOUT(),
1832 qsort(ips
->ip
, ips
->num
, sizeof(struct ctdb_public_ip
),
1833 ctdb_public_ip_cmp
);
1835 ipinfo
= talloc_array(mem_ctx
, struct ctdb_public_ip_info
*, ips
->num
);
1836 if (ipinfo
== NULL
) {
1840 for (i
=0; i
<ips
->num
; i
++) {
1843 pnn
= ips
->ip
[i
].pnn
;
1845 pnn
= ctdb
->cmd_pnn
;
1847 if (pnn
== CTDB_UNKNOWN_PNN
) {
1851 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
,
1853 TIMEOUT(), &ips
->ip
[i
].addr
,
1860 print_ip(mem_ctx
, ctdb
, ips
, ipinfo
, do_all
);
1864 static int control_ipinfo(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1865 int argc
, const char **argv
)
1867 struct ctdb_public_ip_info
*ipinfo
;
1868 ctdb_sock_addr addr
;
1876 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
1878 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
1882 ret
= ctdb_ctrl_get_public_ip_info(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1883 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
1887 printf("Node %u does not know about IP %s\n",
1888 ctdb
->cmd_pnn
, argv
[0]);
1893 printf("Public IP[%s] info on node %u\n",
1894 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1897 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1898 ctdb_sock_addr_to_string(mem_ctx
, &ipinfo
->ip
.addr
, false),
1899 ipinfo
->ip
.pnn
, ipinfo
->ifaces
->num
);
1901 for (i
=0; i
<ipinfo
->ifaces
->num
; i
++) {
1902 struct ctdb_iface
*iface
;
1904 iface
= &ipinfo
->ifaces
->iface
[i
];
1905 iface
->name
[CTDB_IFACE_SIZE
] = '\0';
1906 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1908 iface
->link_state
== 0 ? "down" : "up",
1910 (i
== ipinfo
->active_idx
) ? " (active)" : "");
1916 static int control_ifaces(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1917 int argc
, const char **argv
)
1919 struct ctdb_iface_list
*ifaces
;
1927 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1928 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1933 if (ifaces
->num
== 0) {
1934 printf("No interfaces configured on node %u\n",
1939 if (options
.machinereadable
) {
1940 printf("%s%s%s%s%s%s%s\n", options
.sep
,
1941 "Name", options
.sep
,
1942 "LinkStatus", options
.sep
,
1943 "References", options
.sep
);
1945 printf("Interfaces on node %u\n", ctdb
->cmd_pnn
);
1948 for (i
=0; i
<ifaces
->num
; i
++) {
1949 if (options
.machinereadable
) {
1950 printf("%s%s%s%u%s%u%s\n", options
.sep
,
1951 ifaces
->iface
[i
].name
, options
.sep
,
1952 ifaces
->iface
[i
].link_state
, options
.sep
,
1953 ifaces
->iface
[i
].references
, options
.sep
);
1955 printf("name:%s link:%s references:%u\n",
1956 ifaces
->iface
[i
].name
,
1957 ifaces
->iface
[i
].link_state
? "up" : "down",
1958 ifaces
->iface
[i
].references
);
1965 static int control_setifacelink(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
1966 int argc
, const char **argv
)
1968 struct ctdb_iface_list
*ifaces
;
1969 struct ctdb_iface
*iface
;
1974 usage("setifacelink");
1977 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
1978 fprintf(stderr
, "Interface name '%s' too long\n", argv
[0]);
1982 ret
= ctdb_ctrl_get_ifaces(mem_ctx
, ctdb
->ev
, ctdb
->client
,
1983 ctdb
->cmd_pnn
, TIMEOUT(), &ifaces
);
1986 "Failed to get interface information from node %u\n",
1992 for (i
=0; i
<ifaces
->num
; i
++) {
1993 if (strcmp(ifaces
->iface
[i
].name
, argv
[0]) == 0) {
1994 iface
= &ifaces
->iface
[i
];
1999 if (iface
== NULL
) {
2000 printf("Interface %s not configured on node %u\n",
2001 argv
[0], ctdb
->cmd_pnn
);
2005 if (strcmp(argv
[1], "up") == 0) {
2006 iface
->link_state
= 1;
2007 } else if (strcmp(argv
[1], "down") == 0) {
2008 iface
->link_state
= 0;
2010 usage("setifacelink");
2014 iface
->references
= 0;
2016 ret
= ctdb_ctrl_set_iface_link_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2017 ctdb
->cmd_pnn
, TIMEOUT(), iface
);
2025 static int control_process_exists(TALLOC_CTX
*mem_ctx
,
2026 struct ctdb_context
*ctdb
,
2027 int argc
, const char **argv
)
2034 if (argc
!= 1 && argc
!= 2) {
2035 usage("process-exists");
2038 pid
= atoi(argv
[0]);
2040 srvid
= smb_strtoull(argv
[1], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2047 ret
= ctdb_ctrl_process_exists(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2048 ctdb
->cmd_pnn
, TIMEOUT(), pid
, &status
);
2050 struct ctdb_pid_srvid pid_srvid
;
2052 pid_srvid
.pid
= pid
;
2053 pid_srvid
.srvid
= srvid
;
2055 ret
= ctdb_ctrl_check_pid_srvid(mem_ctx
, ctdb
->ev
,
2056 ctdb
->client
, ctdb
->cmd_pnn
,
2057 TIMEOUT(), &pid_srvid
,
2066 printf("PID %d %s\n", pid
,
2067 (status
== 0 ? "exists" : "does not exist"));
2069 printf("PID %d with SRVID 0x%"PRIx64
" %s\n", pid
, srvid
,
2070 (status
== 0 ? "exists" : "does not exist"));
2075 static int control_getdbmap(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2076 int argc
, const char **argv
)
2078 struct ctdb_dbid_map
*dbmap
;
2086 ret
= ctdb_ctrl_get_dbmap(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2087 ctdb
->cmd_pnn
, TIMEOUT(), &dbmap
);
2092 if (options
.machinereadable
== 1) {
2093 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
2096 "Name", options
.sep
,
2097 "Path", options
.sep
,
2098 "Persistent", options
.sep
,
2099 "Sticky", options
.sep
,
2100 "Unhealthy", options
.sep
,
2101 "Readonly", options
.sep
,
2102 "Replicated", options
.sep
);
2104 printf("Number of databases:%d\n", dbmap
->num
);
2107 for (i
=0; i
<dbmap
->num
; i
++) {
2117 db_id
= dbmap
->dbs
[i
].db_id
;
2119 ret
= ctdb_ctrl_get_dbname(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2120 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2126 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2127 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2133 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2134 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2140 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
2141 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
2142 sticky
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_STICKY
;
2143 replicated
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_REPLICATED
;
2145 if (options
.machinereadable
== 1) {
2146 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s%d%s\n",
2151 !! (persistent
), options
.sep
,
2152 !! (sticky
), options
.sep
,
2153 !! (health
), options
.sep
,
2154 !! (readonly
), options
.sep
,
2155 !! (replicated
), options
.sep
);
2157 printf("dbid:0x%08x name:%s path:%s%s%s%s%s%s\n",
2159 persistent
? " PERSISTENT" : "",
2160 sticky
? " STICKY" : "",
2161 readonly
? " READONLY" : "",
2162 replicated
? " REPLICATED" : "",
2163 health
? " UNHEALTHY" : "");
2166 talloc_free(discard_const(name
));
2167 talloc_free(discard_const(path
));
2168 talloc_free(discard_const(health
));
2174 static int control_getdbstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2175 int argc
, const char **argv
)
2178 const char *db_name
, *db_path
, *db_health
;
2183 usage("getdbstatus");
2186 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2190 ret
= ctdb_ctrl_getdbpath(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2191 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2197 ret
= ctdb_ctrl_db_get_health(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2198 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
2204 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id
, db_name
, db_path
);
2205 printf("PERSISTENT: %s\nREPLICATED: %s\nSTICKY: %s\nREADONLY: %s\n",
2206 (db_flags
& CTDB_DB_FLAGS_PERSISTENT
? "yes" : "no"),
2207 (db_flags
& CTDB_DB_FLAGS_REPLICATED
? "yes" : "no"),
2208 (db_flags
& CTDB_DB_FLAGS_STICKY
? "yes" : "no"),
2209 (db_flags
& CTDB_DB_FLAGS_READONLY
? "yes" : "no"));
2210 printf("HEALTH: %s\n", (db_health
? db_health
: "OK"));
2214 struct dump_record_state
{
2218 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
2220 static void dump_tdb_data(const char *name
, TDB_DATA val
)
2224 fprintf(stdout
, "%s(%zu) = \"", name
, val
.dsize
);
2225 for (i
=0; i
<val
.dsize
; i
++) {
2226 if (ISASCII(val
.dptr
[i
])) {
2227 fprintf(stdout
, "%c", val
.dptr
[i
]);
2229 fprintf(stdout
, "\\%02X", val
.dptr
[i
]);
2232 fprintf(stdout
, "\"\n");
2235 static void dump_ltdb_header(struct ctdb_ltdb_header
*header
)
2237 fprintf(stdout
, "dmaster: %u\n", header
->dmaster
);
2238 fprintf(stdout
, "rsn: %" PRIu64
"\n", header
->rsn
);
2239 fprintf(stdout
, "flags: 0x%08x", header
->flags
);
2240 if (header
->flags
& CTDB_REC_FLAG_MIGRATED_WITH_DATA
) {
2241 fprintf(stdout
, " MIGRATED_WITH_DATA");
2243 if (header
->flags
& CTDB_REC_FLAG_VACUUM_MIGRATED
) {
2244 fprintf(stdout
, " VACUUM_MIGRATED");
2246 if (header
->flags
& CTDB_REC_FLAG_AUTOMATIC
) {
2247 fprintf(stdout
, " AUTOMATIC");
2249 if (header
->flags
& CTDB_REC_RO_HAVE_DELEGATIONS
) {
2250 fprintf(stdout
, " RO_HAVE_DELEGATIONS");
2252 if (header
->flags
& CTDB_REC_RO_HAVE_READONLY
) {
2253 fprintf(stdout
, " RO_HAVE_READONLY");
2255 if (header
->flags
& CTDB_REC_RO_REVOKING_READONLY
) {
2256 fprintf(stdout
, " RO_REVOKING_READONLY");
2258 if (header
->flags
& CTDB_REC_RO_REVOKE_COMPLETE
) {
2259 fprintf(stdout
, " RO_REVOKE_COMPLETE");
2261 fprintf(stdout
, "\n");
2265 static int dump_record(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
2266 TDB_DATA key
, TDB_DATA data
, void *private_data
)
2268 struct dump_record_state
*state
=
2269 (struct dump_record_state
*)private_data
;
2273 dump_tdb_data("key", key
);
2274 dump_ltdb_header(header
);
2275 dump_tdb_data("data", data
);
2276 fprintf(stdout
, "\n");
2281 static int control_catdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2282 int argc
, const char **argv
)
2284 struct ctdb_db_context
*db
;
2285 const char *db_name
;
2288 struct dump_record_state state
;
2295 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2299 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2302 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2308 ret
= ctdb_db_traverse(mem_ctx
, ctdb
->ev
, ctdb
->client
, db
,
2309 ctdb
->cmd_pnn
, TIMEOUT(),
2310 dump_record
, &state
);
2312 printf("Dumped %u records\n", state
.count
);
2317 static int control_cattdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2318 int argc
, const char **argv
)
2320 struct ctdb_db_context
*db
;
2321 const char *db_name
;
2324 struct dump_record_state state
;
2331 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
2335 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2338 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
2343 ret
= ctdb_db_traverse_local(db
, true, true, dump_record
, &state
);
2345 printf("Dumped %u record(s)\n", state
.count
);
2350 static int control_getcapabilities(TALLOC_CTX
*mem_ctx
,
2351 struct ctdb_context
*ctdb
,
2352 int argc
, const char **argv
)
2358 usage("getcapabilities");
2361 ret
= ctdb_ctrl_get_capabilities(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2362 ctdb
->cmd_pnn
, TIMEOUT(), &caps
);
2367 if (options
.machinereadable
== 1) {
2368 printf("%s%s%s%s%s\n",
2370 "LEADER", options
.sep
,
2371 "LMASTER", options
.sep
);
2372 printf("%s%d%s%d%s\n", options
.sep
,
2373 !! (caps
& CTDB_CAP_RECMASTER
), options
.sep
,
2374 !! (caps
& CTDB_CAP_LMASTER
), options
.sep
);
2376 printf("LEADER: %s\n",
2377 (caps
& CTDB_CAP_RECMASTER
) ? "YES" : "NO");
2378 printf("LMASTER: %s\n",
2379 (caps
& CTDB_CAP_LMASTER
) ? "YES" : "NO");
2385 static int control_pnn(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2386 int argc
, const char **argv
)
2388 printf("%u\n", ctdb_client_pnn(ctdb
->client
));
2392 static int control_lvs(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2393 int argc
, const char **argv
)
2395 char *t
, *lvs_helper
= NULL
;
2401 t
= getenv("CTDB_LVS_HELPER");
2403 lvs_helper
= talloc_strdup(mem_ctx
, t
);
2405 lvs_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_lvs",
2406 CTDB_HELPER_BINDIR
);
2409 if (lvs_helper
== NULL
) {
2410 fprintf(stderr
, "Unable to set LVS helper\n");
2414 return run_helper(mem_ctx
, "LVS helper", lvs_helper
, argc
, argv
);
2417 static int control_setdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2418 int argc
, const char **argv
)
2428 found
= debug_level_parse(argv
[0], &log_level
);
2431 "Invalid debug level '%s'. Valid levels are:\n",
2433 fprintf(stderr
, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2437 ret
= ctdb_ctrl_setdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2438 ctdb
->cmd_pnn
, TIMEOUT(), log_level
);
2446 static int control_getdebug(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2447 int argc
, const char **argv
)
2450 const char *log_str
;
2457 ret
= ctdb_ctrl_getdebug(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2458 ctdb
->cmd_pnn
, TIMEOUT(), &loglevel
);
2463 log_str
= debug_level_to_string(loglevel
);
2464 printf("%s\n", log_str
);
2469 static int control_attach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2470 int argc
, const char **argv
)
2472 const char *db_name
;
2473 uint8_t db_flags
= 0;
2476 if (argc
< 1 || argc
> 2) {
2482 if (strcmp(argv
[1], "persistent") == 0) {
2483 db_flags
= CTDB_DB_FLAGS_PERSISTENT
;
2484 } else if (strcmp(argv
[1], "readonly") == 0) {
2485 db_flags
= CTDB_DB_FLAGS_READONLY
;
2486 } else if (strcmp(argv
[1], "sticky") == 0) {
2487 db_flags
= CTDB_DB_FLAGS_STICKY
;
2488 } else if (strcmp(argv
[1], "replicated") == 0) {
2489 db_flags
= CTDB_DB_FLAGS_REPLICATED
;
2495 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
2504 static int control_detach(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2505 int argc
, const char **argv
)
2507 const char *db_name
;
2510 struct ctdb_node_map
*nodemap
;
2519 ret
= ctdb_ctrl_get_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2520 ctdb
->cmd_pnn
, TIMEOUT(), &recmode
);
2525 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
2526 fprintf(stderr
, "Database cannot be detached"
2527 " when recovery is active\n");
2531 nodemap
= get_nodemap(ctdb
, false);
2532 if (nodemap
== NULL
) {
2536 for (j
=0; j
<nodemap
->num
; j
++) {
2539 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DISCONNECTED
) {
2542 if (nodemap
->node
[j
].flags
& NODE_FLAGS_DELETED
) {
2545 if (nodemap
->node
[j
].flags
& NODE_FLAGS_INACTIVE
) {
2546 fprintf(stderr
, "Database cannot be detached on"
2547 " inactive (stopped or banned) node %u\n",
2548 nodemap
->node
[j
].pnn
);
2552 ret
= ctdb_ctrl_get_tunable(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2553 nodemap
->node
[j
].pnn
, TIMEOUT(),
2554 "AllowClientDBAttach", &value
);
2557 "Unable to get tunable AllowClientDBAttach"
2558 " from node %u\n", nodemap
->node
[j
].pnn
);
2564 "Database access is still active on node %u."
2565 " Set AllowclientDBAttach=0 on all nodes.\n",
2566 nodemap
->node
[j
].pnn
);
2572 for (i
=0; i
<argc
; i
++) {
2573 if (! db_exists(mem_ctx
, ctdb
, argv
[i
], &db_id
, &db_name
,
2579 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
2581 "Only volatile databases can be detached\n");
2585 ret
= ctdb_detach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_id
);
2587 fprintf(stderr
, "Database %s detach failed\n", db_name
);
2595 static int control_dumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2596 int argc
, const char **argv
)
2598 const char *mem_str
;
2602 ret
= ctdb_ctrl_dump_memory(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2603 ctdb
->cmd_pnn
, TIMEOUT(), &mem_str
);
2608 n
= write(1, mem_str
, strlen(mem_str
));
2609 if (n
< 0 || (size_t)n
!= strlen(mem_str
)) {
2610 fprintf(stderr
, "Failed to write talloc summary\n");
2617 static void dump_memory(uint64_t srvid
, TDB_DATA data
, void *private_data
)
2619 bool *done
= (bool *)private_data
;
2623 len
= strnlen((const char *)data
.dptr
, data
.dsize
);
2624 n
= write(1, data
.dptr
, len
);
2625 if (n
< 0 || (size_t)n
!= len
) {
2626 fprintf(stderr
, "Failed to write talloc summary\n");
2632 static int control_rddumpmemory(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2633 int argc
, const char **argv
)
2635 struct ctdb_srvid_message msg
= { 0 };
2639 msg
.pnn
= ctdb
->pnn
;
2640 msg
.srvid
= next_srvid(ctdb
);
2642 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2643 msg
.srvid
, dump_memory
, &done
);
2648 ret
= ctdb_message_mem_dump(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2649 ctdb
->cmd_pnn
, &msg
);
2654 ctdb_client_wait(ctdb
->ev
, &done
);
2658 static int control_getpid(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2659 int argc
, const char **argv
)
2664 ret
= ctdb_ctrl_get_pid(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2665 ctdb
->cmd_pnn
, TIMEOUT(), &pid
);
2670 printf("%u\n", pid
);
2674 static int check_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2675 const char *desc
, uint32_t flag
, bool set_flag
)
2677 struct ctdb_node_map
*nodemap
;
2680 nodemap
= get_nodemap(ctdb
, false);
2681 if (nodemap
== NULL
) {
2685 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2686 if (set_flag
== flag_is_set
) {
2688 fprintf(stderr
, "Node %u is already %s\n",
2689 ctdb
->cmd_pnn
, desc
);
2691 fprintf(stderr
, "Node %u is not %s\n",
2692 ctdb
->cmd_pnn
, desc
);
2700 static void wait_for_flags(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2701 uint32_t flag
, bool set_flag
)
2703 struct ctdb_node_map
*nodemap
;
2707 nodemap
= get_nodemap(ctdb
, true);
2708 if (nodemap
== NULL
) {
2710 "Failed to get nodemap, trying again\n");
2715 flag_is_set
= nodemap
->node
[ctdb
->cmd_pnn
].flags
& flag
;
2716 if (flag_is_set
== set_flag
) {
2724 struct ipreallocate_state
{
2729 static void ipreallocate_handler(uint64_t srvid
, TDB_DATA data
,
2732 struct ipreallocate_state
*state
=
2733 (struct ipreallocate_state
*)private_data
;
2735 if (data
.dsize
!= sizeof(int)) {
2740 state
->status
= *(int *)data
.dptr
;
2744 static int ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
)
2746 struct ctdb_srvid_message msg
= { 0 };
2747 struct ipreallocate_state state
;
2750 msg
.pnn
= ctdb
->pnn
;
2751 msg
.srvid
= next_srvid(ctdb
);
2754 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
2756 ipreallocate_handler
, &state
);
2762 ret
= ctdb_message_takeover_run(mem_ctx
, ctdb
->ev
,
2764 CTDB_BROADCAST_CONNECTED
,
2770 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
,
2776 if (state
.status
>= 0) {
2785 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
2790 static int control_disable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2791 int argc
, const char **argv
)
2799 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2800 NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2805 ret
= ctdb_ctrl_disable_node(mem_ctx
,
2811 fprintf(stderr
, "Failed to disable node %u\n", ctdb
->cmd_pnn
);
2815 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, true);
2816 return ipreallocate(mem_ctx
, ctdb
);
2819 static int control_enable(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2820 int argc
, const char **argv
)
2828 ret
= check_flags(mem_ctx
, ctdb
, "disabled",
2829 NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2834 ret
= ctdb_ctrl_enable_node(mem_ctx
,
2840 fprintf(stderr
, "Failed to enable node %u\n", ctdb
->cmd_pnn
);
2844 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_PERMANENTLY_DISABLED
, false);
2845 return ipreallocate(mem_ctx
, ctdb
);
2848 static int control_stop(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2849 int argc
, const char **argv
)
2857 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2858 NODE_FLAGS_STOPPED
, true);
2863 ret
= ctdb_ctrl_stop_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2864 ctdb
->cmd_pnn
, TIMEOUT());
2866 fprintf(stderr
, "Failed to stop node %u\n", ctdb
->cmd_pnn
);
2870 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, true);
2871 return ipreallocate(mem_ctx
, ctdb
);
2874 static int control_continue(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2875 int argc
, const char **argv
)
2883 ret
= check_flags(mem_ctx
, ctdb
, "stopped",
2884 NODE_FLAGS_STOPPED
, false);
2889 ret
= ctdb_ctrl_continue_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2890 ctdb
->cmd_pnn
, TIMEOUT());
2892 fprintf(stderr
, "Failed to continue stopped node %u\n",
2897 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_STOPPED
, false);
2898 return ipreallocate(mem_ctx
, ctdb
);
2901 static int control_ban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2902 int argc
, const char **argv
)
2904 struct ctdb_ban_state ban_state
;
2911 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2912 NODE_FLAGS_BANNED
, true);
2917 ban_state
.pnn
= ctdb
->cmd_pnn
;
2918 ban_state
.time
= smb_strtoul(argv
[0], NULL
, 0, &ret
, SMB_STR_STANDARD
);
2923 if (ban_state
.time
== 0) {
2924 fprintf(stderr
, "Ban time cannot be zero\n");
2928 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2929 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2931 fprintf(stderr
, "Failed to ban node %u\n", ctdb
->cmd_pnn
);
2935 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, true);
2936 return ipreallocate(mem_ctx
, ctdb
);
2940 static int control_unban(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2941 int argc
, const char **argv
)
2943 struct ctdb_ban_state ban_state
;
2950 ret
= check_flags(mem_ctx
, ctdb
, "banned",
2951 NODE_FLAGS_BANNED
, false);
2956 ban_state
.pnn
= ctdb
->cmd_pnn
;
2959 ret
= ctdb_ctrl_set_ban_state(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2960 ctdb
->cmd_pnn
, TIMEOUT(), &ban_state
);
2962 fprintf(stderr
, "Failed to unban node %u\n", ctdb
->cmd_pnn
);
2966 wait_for_flags(mem_ctx
, ctdb
, NODE_FLAGS_BANNED
, false);
2967 return ipreallocate(mem_ctx
, ctdb
);
2971 static void wait_for_shutdown(void *private_data
)
2973 bool *done
= (bool *)private_data
;
2978 static int control_shutdown(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
2979 int argc
, const char **argv
)
2988 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
2989 ctdb_client_set_disconnect_callback(ctdb
->client
,
2994 ret
= ctdb_ctrl_shutdown(mem_ctx
, ctdb
->ev
, ctdb
->client
,
2995 ctdb
->cmd_pnn
, TIMEOUT());
2997 fprintf(stderr
, "Unable to shutdown node %u\n", ctdb
->cmd_pnn
);
3001 if (ctdb
->pnn
== ctdb
->cmd_pnn
) {
3002 ctdb_client_wait(ctdb
->ev
, &done
);
3008 static int get_generation(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3009 uint32_t *generation
)
3013 struct ctdb_vnn_map
*vnnmap
;
3017 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
3019 fprintf(stderr
, "Failed to find leader\n");
3023 ret
= ctdb_ctrl_get_recmode(mem_ctx
,
3031 "Failed to get recovery mode from node %u\n",
3036 if (recmode
== CTDB_RECOVERY_ACTIVE
) {
3041 ret
= ctdb_ctrl_getvnnmap(mem_ctx
,
3049 "Failed to get generation from node %u\n",
3054 if (vnnmap
->generation
== INVALID_GENERATION
) {
3055 talloc_free(vnnmap
);
3060 *generation
= vnnmap
->generation
;
3061 talloc_free(vnnmap
);
3066 static int control_recover(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3067 int argc
, const char **argv
)
3069 uint32_t generation
, next_generation
;
3076 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
3081 ret
= ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3082 ctdb
->cmd_pnn
, TIMEOUT(),
3083 CTDB_RECOVERY_ACTIVE
);
3085 fprintf(stderr
, "Failed to set recovery mode active\n");
3090 ret
= get_generation(mem_ctx
, ctdb
, &next_generation
);
3093 "Failed to confirm end of recovery\n");
3097 if (next_generation
!= generation
) {
3107 static int control_ipreallocate(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3108 int argc
, const char **argv
)
3111 usage("ipreallocate");
3114 return ipreallocate(mem_ctx
, ctdb
);
3117 static int control_gratarp(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3118 int argc
, const char **argv
)
3120 struct ctdb_addr_info addr_info
;
3127 ret
= ctdb_sock_addr_from_string(argv
[0], &addr_info
.addr
, false);
3129 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3132 addr_info
.iface
= argv
[1];
3134 ret
= ctdb_ctrl_send_gratuitous_arp(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3135 ctdb
->cmd_pnn
, TIMEOUT(),
3138 fprintf(stderr
, "Unable to send gratuitous arp from node %u\n",
3146 static int control_tickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3147 int argc
, const char **argv
)
3149 ctdb_sock_addr src
, dst
;
3152 if (argc
!= 0 && argc
!= 2) {
3157 struct ctdb_connection_list
*clist
;
3159 unsigned int num_failed
;
3161 /* Client first but the src/dst logic is confused */
3162 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3168 for (i
= 0; i
< clist
->num
; i
++) {
3169 ret
= ctdb_sys_send_tcp(&clist
->conn
[i
].src
,
3170 &clist
->conn
[i
].dst
,
3179 if (num_failed
> 0) {
3180 fprintf(stderr
, "Failed to send %d tickles\n",
3189 ret
= ctdb_sock_addr_from_string(argv
[0], &src
, true);
3191 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3195 ret
= ctdb_sock_addr_from_string(argv
[1], &dst
, true);
3197 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3201 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
3203 fprintf(stderr
, "Failed to send tickle ack\n");
3210 static int control_gettickles(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3211 int argc
, const char **argv
)
3213 ctdb_sock_addr addr
;
3214 struct ctdb_tickle_list
*tickles
;
3219 if (argc
< 1 || argc
> 2) {
3220 usage("gettickles");
3224 port
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3230 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3232 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3235 ctdb_sock_addr_set_port(&addr
, port
);
3237 ret
= ctdb_ctrl_get_tcp_tickle_list(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3238 ctdb
->cmd_pnn
, TIMEOUT(), &addr
,
3241 fprintf(stderr
, "Failed to get list of connections\n");
3245 if (options
.machinereadable
) {
3246 printf("%s%s%s%s%s%s%s%s%s\n",
3248 "Source IP", options
.sep
,
3249 "Port", options
.sep
,
3250 "Destination IP", options
.sep
,
3251 "Port", options
.sep
);
3252 for (i
=0; i
<tickles
->num
; i
++) {
3253 printf("%s%s%s%u%s%s%s%u%s\n", options
.sep
,
3254 ctdb_sock_addr_to_string(
3255 mem_ctx
, &tickles
->conn
[i
].src
, false),
3257 ntohs(tickles
->conn
[i
].src
.ip
.sin_port
),
3259 ctdb_sock_addr_to_string(
3260 mem_ctx
, &tickles
->conn
[i
].dst
, false),
3262 ntohs(tickles
->conn
[i
].dst
.ip
.sin_port
),
3266 printf("Connections for IP: %s\n",
3267 ctdb_sock_addr_to_string(mem_ctx
,
3268 &tickles
->addr
, false));
3269 printf("Num connections: %u\n", tickles
->num
);
3270 for (i
=0; i
<tickles
->num
; i
++) {
3271 printf("SRC: %s DST: %s\n",
3272 ctdb_sock_addr_to_string(
3273 mem_ctx
, &tickles
->conn
[i
].src
, true),
3274 ctdb_sock_addr_to_string(
3275 mem_ctx
, &tickles
->conn
[i
].dst
, true));
3279 talloc_free(tickles
);
3283 typedef void (*clist_request_func
)(struct ctdb_req_control
*request
,
3284 struct ctdb_connection
*conn
);
3286 typedef int (*clist_reply_func
)(struct ctdb_reply_control
*reply
);
3288 struct process_clist_state
{
3289 struct ctdb_connection_list
*clist
;
3291 unsigned int num_failed
, num_total
;
3292 clist_reply_func reply_func
;
3295 static void process_clist_done(struct tevent_req
*subreq
);
3297 static struct tevent_req
*process_clist_send(
3298 TALLOC_CTX
*mem_ctx
,
3299 struct ctdb_context
*ctdb
,
3300 struct ctdb_connection_list
*clist
,
3301 clist_request_func request_func
,
3302 clist_reply_func reply_func
)
3304 struct tevent_req
*req
, *subreq
;
3305 struct process_clist_state
*state
;
3306 struct ctdb_req_control request
;
3309 req
= tevent_req_create(mem_ctx
, &state
, struct process_clist_state
);
3314 state
->clist
= clist
;
3315 state
->reply_func
= reply_func
;
3317 for (i
= 0; i
< clist
->num
; i
++) {
3318 request_func(&request
, &clist
->conn
[i
]);
3319 subreq
= ctdb_client_control_send(state
, ctdb
->ev
,
3320 ctdb
->client
, ctdb
->cmd_pnn
,
3321 TIMEOUT(), &request
);
3322 if (tevent_req_nomem(subreq
, req
)) {
3323 return tevent_req_post(req
, ctdb
->ev
);
3325 tevent_req_set_callback(subreq
, process_clist_done
, req
);
3331 static void process_clist_done(struct tevent_req
*subreq
)
3333 struct tevent_req
*req
= tevent_req_callback_data(
3334 subreq
, struct tevent_req
);
3335 struct process_clist_state
*state
= tevent_req_data(
3336 req
, struct process_clist_state
);
3337 struct ctdb_reply_control
*reply
;
3341 status
= ctdb_client_control_recv(subreq
, NULL
, state
, &reply
);
3342 TALLOC_FREE(subreq
);
3344 state
->num_failed
+= 1;
3348 ret
= state
->reply_func(reply
);
3350 state
->num_failed
+= 1;
3355 state
->num_total
+= 1;
3356 if (state
->num_total
== state
->clist
->num
) {
3357 tevent_req_done(req
);
3361 static int process_clist_recv(struct tevent_req
*req
)
3363 struct process_clist_state
*state
= tevent_req_data(
3364 req
, struct process_clist_state
);
3366 return state
->num_failed
;
3369 static int control_addtickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3370 int argc
, const char **argv
)
3372 struct ctdb_connection conn
;
3375 if (argc
!= 0 && argc
!= 2) {
3380 struct ctdb_connection_list
*clist
;
3381 struct tevent_req
*req
;
3383 /* Client first but the src/dst logic is confused */
3384 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3388 if (clist
->num
== 0) {
3392 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3393 ctdb_req_control_tcp_add_delayed_update
,
3394 ctdb_reply_control_tcp_add_delayed_update
);
3400 tevent_req_poll(req
, ctdb
->ev
);
3403 ret
= process_clist_recv(req
);
3405 fprintf(stderr
, "Failed to add %d tickles\n", ret
);
3412 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3414 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3417 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3419 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3423 ret
= ctdb_ctrl_tcp_add_delayed_update(mem_ctx
, ctdb
->ev
,
3424 ctdb
->client
, ctdb
->cmd_pnn
,
3427 fprintf(stderr
, "Failed to register connection\n");
3434 static int control_deltickle(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3435 int argc
, const char **argv
)
3437 struct ctdb_connection conn
;
3440 if (argc
!= 0 && argc
!= 2) {
3445 struct ctdb_connection_list
*clist
;
3446 struct tevent_req
*req
;
3448 /* Client first but the src/dst logic is confused */
3449 ret
= ctdb_connection_list_read(mem_ctx
, 0, false, &clist
);
3453 if (clist
->num
== 0) {
3457 req
= process_clist_send(mem_ctx
, ctdb
, clist
,
3458 ctdb_req_control_tcp_remove
,
3459 ctdb_reply_control_tcp_remove
);
3465 tevent_req_poll(req
, ctdb
->ev
);
3468 ret
= process_clist_recv(req
);
3470 fprintf(stderr
, "Failed to remove %d tickles\n", ret
);
3477 ret
= ctdb_sock_addr_from_string(argv
[0], &conn
.src
, true);
3479 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3482 ret
= ctdb_sock_addr_from_string(argv
[1], &conn
.dst
, true);
3484 fprintf(stderr
, "Invalid IP address %s\n", argv
[1]);
3488 ret
= ctdb_ctrl_tcp_remove(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3489 ctdb
->cmd_pnn
, TIMEOUT(), &conn
);
3491 fprintf(stderr
, "Failed to unregister connection\n");
3498 static int control_listnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3499 int argc
, const char **argv
)
3501 struct ctdb_node_map
*nodemap
;
3508 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
3509 if (nodemap
== NULL
) {
3513 for (i
=0; i
<nodemap
->num
; i
++) {
3514 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3518 if (options
.machinereadable
) {
3519 printf("%s%u%s%s%s\n", options
.sep
,
3520 nodemap
->node
[i
].pnn
, options
.sep
,
3521 ctdb_sock_addr_to_string(
3522 mem_ctx
, &nodemap
->node
[i
].addr
, false),
3526 ctdb_sock_addr_to_string(
3527 mem_ctx
, &nodemap
->node
[i
].addr
, false));
3534 static bool nodemap_identical(struct ctdb_node_map
*nodemap1
,
3535 struct ctdb_node_map
*nodemap2
)
3539 if (nodemap1
->num
!= nodemap2
->num
) {
3543 for (i
=0; i
<nodemap1
->num
; i
++) {
3544 struct ctdb_node_and_flags
*n1
, *n2
;
3546 n1
= &nodemap1
->node
[i
];
3547 n2
= &nodemap2
->node
[i
];
3549 if ((n1
->pnn
!= n2
->pnn
) ||
3550 (n1
->flags
!= n2
->flags
) ||
3551 ! ctdb_sock_addr_same_ip(&n1
->addr
, &n2
->addr
)) {
3559 static int check_node_file_changes(TALLOC_CTX
*mem_ctx
,
3560 struct ctdb_node_map
*nm
,
3561 struct ctdb_node_map
*fnm
,
3565 bool check_failed
= false;
3569 for (i
=0; i
<nm
->num
; i
++) {
3570 if (i
>= fnm
->num
) {
3572 "Node %u (%s) missing from nodes file\n",
3574 ctdb_sock_addr_to_string(
3575 mem_ctx
, &nm
->node
[i
].addr
, false));
3576 check_failed
= true;
3579 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
&&
3580 fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3581 /* Node remains deleted */
3585 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) &&
3586 ! (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
)) {
3587 /* Node not newly nor previously deleted */
3588 if (! ctdb_same_ip(&nm
->node
[i
].addr
,
3589 &fnm
->node
[i
].addr
)) {
3591 "Node %u has changed IP address"
3592 " (was %s, now %s)\n",
3594 ctdb_sock_addr_to_string(
3596 &nm
->node
[i
].addr
, false),
3597 ctdb_sock_addr_to_string(
3599 &fnm
->node
[i
].addr
, false));
3600 check_failed
= true;
3602 if (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3604 "WARNING: Node %u is disconnected."
3605 " You MUST fix this node manually!\n",
3612 if (fnm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3613 /* Node is being deleted */
3614 printf("Node %u is DELETED\n", nm
->node
[i
].pnn
);
3616 if (! (nm
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
)) {
3618 "ERROR: Node %u is still connected\n",
3620 check_failed
= true;
3625 if (nm
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
3626 /* Node was previously deleted */
3627 printf("Node %u is UNDELETED\n", nm
->node
[i
].pnn
);
3634 "ERROR: Nodes will not be reloaded due to previous error\n");
3638 /* Leftover nodes in file are NEW */
3639 for (; i
< fnm
->num
; i
++) {
3640 printf("Node %u is NEW\n", fnm
->node
[i
].pnn
);
3647 struct disable_recoveries_state
{
3649 unsigned int node_count
;
3655 static void disable_recoveries_handler(uint64_t srvid
, TDB_DATA data
,
3658 struct disable_recoveries_state
*state
=
3659 (struct disable_recoveries_state
*)private_data
;
3663 if (data
.dsize
!= sizeof(int)) {
3668 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3669 ret
= *(int *)data
.dptr
;
3671 state
->status
= ret
;
3675 for (i
=0; i
<state
->node_count
; i
++) {
3676 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
3677 state
->reply
[i
] = true;
3683 for (i
=0; i
<state
->node_count
; i
++) {
3684 if (! state
->reply
[i
]) {
3685 state
->done
= false;
3691 static int disable_recoveries(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3692 uint32_t timeout
, uint32_t *pnn_list
, int count
)
3694 struct ctdb_disable_message disable
= { 0 };
3695 struct disable_recoveries_state state
;
3698 disable
.pnn
= ctdb
->pnn
;
3699 disable
.srvid
= next_srvid(ctdb
);
3700 disable
.timeout
= timeout
;
3702 state
.pnn_list
= pnn_list
;
3703 state
.node_count
= count
;
3706 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
3707 if (state
.reply
== NULL
) {
3711 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
3713 disable_recoveries_handler
,
3719 for (i
=0; i
<count
; i
++) {
3720 ret
= ctdb_message_disable_recoveries(mem_ctx
, ctdb
->ev
,
3729 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
3731 fprintf(stderr
, "Timed out waiting to disable recoveries\n");
3733 ret
= (state
.status
>= 0 ? 0 : 1);
3737 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
3738 disable
.srvid
, &state
);
3742 static int control_reloadnodes(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3743 int argc
, const char **argv
)
3745 struct ctdb_node_map
*nodemap
= NULL
;
3746 struct ctdb_node_map
*file_nodemap
;
3747 struct ctdb_node_map
*remote_nodemap
;
3748 struct ctdb_req_control request
;
3749 struct ctdb_reply_control
**reply
;
3756 nodemap
= get_nodemap(ctdb
, false);
3757 if (nodemap
== NULL
) {
3761 file_nodemap
= read_nodes_file(mem_ctx
, ctdb
->pnn
);
3762 if (file_nodemap
== NULL
) {
3766 for (i
=0; i
<nodemap
->num
; i
++) {
3767 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
3771 ret
= ctdb_ctrl_get_nodes_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3772 nodemap
->node
[i
].pnn
, TIMEOUT(),
3776 "ERROR: Failed to get nodes file from node %u\n",
3777 nodemap
->node
[i
].pnn
);
3781 if (! nodemap_identical(file_nodemap
, remote_nodemap
)) {
3783 "ERROR: Nodes file on node %u differs"
3784 " from current node (%u)\n",
3785 nodemap
->node
[i
].pnn
, ctdb
->pnn
);
3790 ret
= check_node_file_changes(mem_ctx
, nodemap
, file_nodemap
, &reload
);
3796 fprintf(stderr
, "No change in nodes file,"
3797 " skipping unnecessary reload\n");
3801 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
3802 mem_ctx
, &pnn_list
);
3804 fprintf(stderr
, "Memory allocation error\n");
3808 ret
= disable_recoveries(mem_ctx
, ctdb
, 2*options
.timelimit
,
3811 fprintf(stderr
, "Failed to disable recoveries\n");
3815 ctdb_req_control_reload_nodes_file(&request
);
3816 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3817 pnn_list
, count
, TIMEOUT(),
3818 &request
, NULL
, &reply
);
3820 bool failed
= false;
3823 for (j
=0; j
<count
; j
++) {
3824 ret
= ctdb_reply_control_reload_nodes_file(reply
[j
]);
3827 "Node %u failed to reload nodes\n",
3834 "You MUST fix failed nodes manually!\n");
3838 ret
= disable_recoveries(mem_ctx
, ctdb
, 0, pnn_list
, count
);
3840 fprintf(stderr
, "Failed to enable recoveries\n");
3847 static int moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3848 ctdb_sock_addr
*addr
, uint32_t pnn
)
3850 struct ctdb_public_ip_list
*pubip_list
;
3851 struct ctdb_public_ip pubip
;
3852 struct ctdb_node_map
*nodemap
;
3853 struct ctdb_req_control request
;
3857 uint32_t *connected_pnn
= NULL
;
3858 int connected_count
;
3860 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3861 pnn
, TIMEOUT(), false, &pubip_list
);
3863 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
3868 for (i
=0; i
<pubip_list
->num
; i
++) {
3869 if (ctdb_same_ip(addr
, &pubip_list
->ip
[i
].addr
)) {
3874 if (i
== pubip_list
->num
) {
3875 fprintf(stderr
, "Node %u CANNOT host IP address %s\n",
3876 pnn
, ctdb_sock_addr_to_string(mem_ctx
, addr
, false));
3880 nodemap
= get_nodemap(ctdb
, false);
3881 if (nodemap
== NULL
) {
3885 count
= list_of_active_nodes(nodemap
, pnn
, mem_ctx
, &pnn_list
);
3887 fprintf(stderr
, "Memory allocation error\n");
3891 connected_count
= list_of_connected_nodes(nodemap
,
3895 if (connected_count
<= 0) {
3896 fprintf(stderr
, "Memory allocation error\n");
3901 * Disable takeover runs on all connected nodes. A reply
3902 * indicating success is needed from each node so all nodes
3903 * will need to be active.
3905 * A check could be added to not allow reloading of IPs when
3906 * there are disconnected nodes. However, this should
3907 * probably be left up to the administrator.
3909 ret
= disable_takeover_runs(mem_ctx
,
3911 2*options
.timelimit
,
3915 fprintf(stderr
, "Failed to disable takeover runs\n");
3921 ctdb_req_control_release_ip(&request
, &pubip
);
3923 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3924 pnn_list
, count
, TIMEOUT(),
3925 &request
, NULL
, NULL
);
3927 fprintf(stderr
, "Failed to release IP on nodes\n");
3931 ret
= ctdb_ctrl_takeover_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
3932 pnn
, TIMEOUT(), &pubip
);
3934 fprintf(stderr
, "Failed to takeover IP on node %u\n", pnn
);
3939 * It isn't strictly necessary to wait until takeover runs are
3940 * re-enabled but doing so can't hurt.
3942 ret
= disable_takeover_runs(mem_ctx
,
3948 fprintf(stderr
, "Failed to enable takeover runs\n");
3952 return send_ipreallocated_control_to_nodes(mem_ctx
,
3958 static int control_moveip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
3959 int argc
, const char **argv
)
3961 ctdb_sock_addr addr
;
3970 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
3972 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
3976 pnn
= smb_strtoul(argv
[1], NULL
, 10, &ret
, SMB_STR_STANDARD
);
3977 if (pnn
== CTDB_UNKNOWN_PNN
|| ret
!= 0) {
3978 fprintf(stderr
, "Invalid PNN %s\n", argv
[1]);
3982 while (retries
< 5) {
3983 ret
= moveip(mem_ctx
, ctdb
, &addr
, pnn
);
3993 fprintf(stderr
, "Failed to move IP %s to node %u\n",
4001 static int rebalancenode(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4006 ret
= ctdb_message_rebalance_node(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4007 CTDB_BROADCAST_CONNECTED
, pnn
);
4010 "Failed to ask leader to distribute IPs\n");
4017 static int control_addip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4018 int argc
, const char **argv
)
4020 ctdb_sock_addr addr
;
4021 struct ctdb_public_ip_list
*pubip_list
;
4022 struct ctdb_addr_info addr_info
;
4023 unsigned int mask
, i
;
4024 int ret
, retries
= 0;
4030 ret
= ctdb_sock_addr_mask_from_string(argv
[0], &addr
, &mask
);
4032 fprintf(stderr
, "Invalid IP/Mask %s\n", argv
[0]);
4036 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4037 ctdb
->cmd_pnn
, TIMEOUT(),
4038 false, &pubip_list
);
4040 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
4045 for (i
=0; i
<pubip_list
->num
; i
++) {
4046 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
4047 fprintf(stderr
, "Node already knows about IP %s\n",
4048 ctdb_sock_addr_to_string(mem_ctx
,
4054 addr_info
.addr
= addr
;
4055 addr_info
.mask
= mask
;
4056 addr_info
.iface
= argv
[1];
4058 while (retries
< 5) {
4059 ret
= ctdb_ctrl_add_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4060 ctdb
->cmd_pnn
, TIMEOUT(),
4071 fprintf(stderr
, "Failed to add public IP to node %u."
4072 " Giving up\n", ctdb
->cmd_pnn
);
4076 ret
= rebalancenode(mem_ctx
, ctdb
, ctdb
->cmd_pnn
);
4082 * CTDB_CONTROL_ADD_PUBLIC_IP will implicitly trigger
4083 * CTDB_SRVID_TAKEOVER_RUN broadcast to all connected nodes.
4085 * That means CTDB_{CONTROL,EVENT,SRVID}_IPREALLOCATED is
4086 * triggered at the end of the takeover run...
4088 * So we don't need to call ipreallocate() nor
4089 * send_ipreallocated_control_to_nodes() here...
4095 static int control_delip(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4096 int argc
, const char **argv
)
4098 ctdb_sock_addr addr
;
4099 struct ctdb_public_ip_list
*pubip_list
;
4100 struct ctdb_addr_info addr_info
;
4108 ret
= ctdb_sock_addr_from_string(argv
[0], &addr
, false);
4110 fprintf(stderr
, "Invalid IP address %s\n", argv
[0]);
4114 ret
= ctdb_ctrl_get_public_ips(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4115 ctdb
->cmd_pnn
, TIMEOUT(),
4116 false, &pubip_list
);
4118 fprintf(stderr
, "Failed to get Public IPs from node %u\n",
4123 for (i
=0; i
<pubip_list
->num
; i
++) {
4124 if (ctdb_same_ip(&addr
, &pubip_list
->ip
[i
].addr
)) {
4129 if (i
== pubip_list
->num
) {
4130 fprintf(stderr
, "Node does not know about IP address %s\n",
4131 ctdb_sock_addr_to_string(mem_ctx
, &addr
, false));
4135 addr_info
.addr
= addr
;
4137 addr_info
.iface
= NULL
;
4139 ret
= ctdb_ctrl_del_public_ip(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4140 ctdb
->cmd_pnn
, TIMEOUT(), &addr_info
);
4142 fprintf(stderr
, "Failed to delete public IP from node %u\n",
4148 * CTDB_CONTROL_DEL_PUBLIC_IP only marks the public ip
4149 * with pending_delete if it's still in use.
4151 * Any later takeover run will really move the public ip
4152 * away from the local node and finally removes it.
4154 * That means CTDB_{CONTROL,EVENT,SRVID}_IPREALLOCATED is
4155 * triggered at the end of the takeover run that actually
4156 * moves the public ip away.
4158 * So we don't need to call ipreallocate() nor
4159 * send_ipreallocated_control_to_nodes() here...
4165 #define DB_VERSION 3
4166 #define MAX_DB_NAME 64
4167 #define MAX_REC_BUFFER_SIZE (100*1000)
4170 unsigned long version
;
4172 unsigned long flags
;
4175 char name
[MAX_DB_NAME
];
4178 struct backup_state
{
4179 TALLOC_CTX
*mem_ctx
;
4180 struct ctdb_rec_buffer
*recbuf
;
4183 unsigned int nbuf
, nrec
;
4186 static int backup_handler(uint32_t reqid
, struct ctdb_ltdb_header
*header
,
4187 TDB_DATA key
, TDB_DATA data
, void *private_data
)
4189 struct backup_state
*state
= (struct backup_state
*)private_data
;
4193 if (state
->recbuf
== NULL
) {
4194 state
->recbuf
= ctdb_rec_buffer_init(state
->mem_ctx
,
4196 if (state
->recbuf
== NULL
) {
4201 ret
= ctdb_rec_buffer_add(state
->recbuf
, state
->recbuf
, reqid
,
4207 len
= ctdb_rec_buffer_len(state
->recbuf
);
4208 if (len
< MAX_REC_BUFFER_SIZE
) {
4212 ret
= ctdb_rec_buffer_write(state
->recbuf
, state
->fd
);
4214 fprintf(stderr
, "Failed to write records to backup file\n");
4219 state
->nrec
+= state
->recbuf
->count
;
4220 TALLOC_FREE(state
->recbuf
);
4225 static int control_backupdb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4226 int argc
, const char **argv
)
4228 const char *db_name
;
4229 struct ctdb_db_context
*db
;
4232 struct backup_state state
;
4233 struct db_header db_hdr
;
4240 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4244 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4247 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4251 fd
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4254 fprintf(stderr
, "Failed to open file %s for writing\n",
4259 /* Write empty header first */
4260 ZERO_STRUCT(db_hdr
);
4261 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4265 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4269 state
.mem_ctx
= mem_ctx
;
4270 state
.recbuf
= NULL
;
4275 ret
= ctdb_db_traverse_local(db
, true, false, backup_handler
, &state
);
4277 fprintf(stderr
, "Failed to collect records from DB %s\n",
4283 if (state
.recbuf
!= NULL
) {
4284 ret
= ctdb_rec_buffer_write(state
.recbuf
, state
.fd
);
4287 "Failed to write records to backup file\n");
4293 state
.nrec
+= state
.recbuf
->count
;
4294 TALLOC_FREE(state
.recbuf
);
4297 db_hdr
.version
= DB_VERSION
;
4298 db_hdr
.timestamp
= time(NULL
);
4299 db_hdr
.flags
= db_flags
;
4300 db_hdr
.nbuf
= state
.nbuf
;
4301 db_hdr
.nrec
= state
.nrec
;
4302 strncpy(db_hdr
.name
, db_name
, MAX_DB_NAME
-1);
4304 lseek(fd
, 0, SEEK_SET
);
4305 ret
= write(fd
, &db_hdr
, sizeof(struct db_header
));
4309 fprintf(stderr
, "Failed to write header to file %s\n", argv
[1]);
4314 printf("Database backed up to %s\n", argv
[1]);
4318 static int control_restoredb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4319 int argc
, const char **argv
)
4321 const char *db_name
= NULL
;
4322 struct ctdb_db_context
*db
;
4323 struct db_header db_hdr
;
4324 struct ctdb_node_map
*nodemap
;
4325 struct ctdb_req_control request
;
4326 struct ctdb_reply_control
**reply
;
4327 struct ctdb_transdb wipedb
;
4328 struct ctdb_pulldb_ext pulldb
;
4329 struct ctdb_rec_buffer
*recbuf
;
4330 uint32_t generation
;
4335 unsigned long i
, count
;
4339 if (argc
< 1 || argc
> 2) {
4343 fd
= open(argv
[0], O_RDONLY
, 0600);
4346 fprintf(stderr
, "Failed to open file %s for reading\n",
4355 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4359 fprintf(stderr
, "Failed to read db header from file %s\n",
4363 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4365 if (db_hdr
.version
!= DB_VERSION
) {
4367 "Wrong version of backup file, expected %u, got %lu\n",
4368 DB_VERSION
, db_hdr
.version
);
4373 if (db_name
== NULL
) {
4374 db_name
= db_hdr
.name
;
4377 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4378 localtime(&db_hdr
.timestamp
));
4379 printf("Restoring database %s from backup @ %s\n", db_name
, timebuf
);
4381 db_flags
= db_hdr
.flags
& 0xff;
4382 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4385 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4390 nodemap
= get_nodemap(ctdb
, false);
4391 if (nodemap
== NULL
) {
4392 fprintf(stderr
, "Failed to get nodemap\n");
4397 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4399 fprintf(stderr
, "Failed to get current generation\n");
4404 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4411 wipedb
.db_id
= ctdb_db_id(db
);
4412 wipedb
.tid
= generation
;
4414 ctdb_req_control_db_freeze(&request
, wipedb
.db_id
);
4415 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4416 ctdb
->client
, pnn_list
, count
,
4417 TIMEOUT(), &request
, NULL
, NULL
);
4423 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4424 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4425 pnn_list
, count
, TIMEOUT(),
4426 &request
, NULL
, NULL
);
4431 ctdb_req_control_wipe_database(&request
, &wipedb
);
4432 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4433 pnn_list
, count
, TIMEOUT(),
4434 &request
, NULL
, NULL
);
4439 pulldb
.db_id
= ctdb_db_id(db
);
4441 pulldb
.srvid
= SRVID_CTDB_PUSHDB
;
4443 ctdb_req_control_db_push_start(&request
, &pulldb
);
4444 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4445 pnn_list
, count
, TIMEOUT(),
4446 &request
, NULL
, NULL
);
4451 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4452 struct ctdb_req_message message
;
4456 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4461 data
.dsize
= ctdb_rec_buffer_len(recbuf
);
4462 data
.dptr
= talloc_size(mem_ctx
, data
.dsize
);
4463 if (data
.dptr
== NULL
) {
4467 ctdb_rec_buffer_push(recbuf
, data
.dptr
, &np
);
4469 message
.srvid
= pulldb
.srvid
;
4470 message
.data
.data
= data
;
4472 ret
= ctdb_client_message_multi(mem_ctx
, ctdb
->ev
,
4480 talloc_free(recbuf
);
4481 talloc_free(data
.dptr
);
4484 ctdb_req_control_db_push_confirm(&request
, pulldb
.db_id
);
4485 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4486 pnn_list
, count
, TIMEOUT(),
4487 &request
, NULL
, &reply
);
4492 for (i
=0; i
<count
; i
++) {
4493 uint32_t num_records
;
4495 ret
= ctdb_reply_control_db_push_confirm(reply
[i
],
4498 fprintf(stderr
, "Invalid response from node %u\n",
4503 if (num_records
!= db_hdr
.nrec
) {
4504 fprintf(stderr
, "Node %u received %u of %lu records\n",
4505 pnn_list
[i
], num_records
, db_hdr
.nrec
);
4510 ctdb_req_control_db_set_healthy(&request
, wipedb
.db_id
);
4511 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4512 pnn_list
, count
, TIMEOUT(),
4513 &request
, NULL
, NULL
);
4518 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4519 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4520 pnn_list
, count
, TIMEOUT(),
4521 &request
, NULL
, NULL
);
4526 ctdb_req_control_db_thaw(&request
, wipedb
.db_id
);
4527 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4528 ctdb
->client
, pnn_list
, count
,
4529 TIMEOUT(), &request
, NULL
, NULL
);
4534 printf("Database %s restored\n", db_name
);
4541 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4542 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4546 struct dumpdbbackup_state
{
4547 ctdb_rec_parser_func_t parser
;
4548 struct dump_record_state sub_state
;
4551 static int dumpdbbackup_handler(uint32_t reqid
,
4552 struct ctdb_ltdb_header
*header
,
4553 TDB_DATA key
, TDB_DATA data
,
4556 struct dumpdbbackup_state
*state
=
4557 (struct dumpdbbackup_state
*)private_data
;
4558 struct ctdb_ltdb_header hdr
;
4561 ret
= ctdb_ltdb_header_extract(&data
, &hdr
);
4566 return state
->parser(reqid
, &hdr
, key
, data
, &state
->sub_state
);
4569 static int control_dumpdbbackup(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4570 int argc
, const char **argv
)
4572 struct db_header db_hdr
;
4574 struct dumpdbbackup_state state
;
4580 usage("dumpbackup");
4583 fd
= open(argv
[0], O_RDONLY
, 0600);
4586 fprintf(stderr
, "Failed to open file %s for reading\n",
4591 n
= read(fd
, &db_hdr
, sizeof(struct db_header
));
4595 fprintf(stderr
, "Failed to read db header from file %s\n",
4599 db_hdr
.name
[sizeof(db_hdr
.name
)-1] = '\0';
4601 if (db_hdr
.version
!= DB_VERSION
) {
4603 "Wrong version of backup file, expected %u, got %lu\n",
4604 DB_VERSION
, db_hdr
.version
);
4609 strftime(timebuf
, sizeof(timebuf
)-1, "%Y/%m/%d %H:%M:%S",
4610 localtime(&db_hdr
.timestamp
));
4611 printf("Dumping database %s from backup @ %s\n",
4612 db_hdr
.name
, timebuf
);
4614 state
.parser
= dump_record
;
4615 state
.sub_state
.count
= 0;
4617 for (i
=0; i
<db_hdr
.nbuf
; i
++) {
4618 struct ctdb_rec_buffer
*recbuf
;
4620 ret
= ctdb_rec_buffer_read(fd
, mem_ctx
, &recbuf
);
4622 fprintf(stderr
, "Failed to read records\n");
4627 ret
= ctdb_rec_buffer_traverse(recbuf
, dumpdbbackup_handler
,
4630 fprintf(stderr
, "Failed to dump records\n");
4637 printf("Dumped %u record(s)\n", state
.sub_state
.count
);
4641 static int control_wipedb(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4642 int argc
, const char **argv
)
4644 const char *db_name
;
4645 struct ctdb_db_context
*db
;
4648 struct ctdb_node_map
*nodemap
;
4649 struct ctdb_req_control request
;
4650 struct ctdb_transdb wipedb
;
4651 uint32_t generation
;
4659 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, &db_flags
)) {
4663 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
4666 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
4670 nodemap
= get_nodemap(ctdb
, false);
4671 if (nodemap
== NULL
) {
4672 fprintf(stderr
, "Failed to get nodemap\n");
4676 ret
= get_generation(mem_ctx
, ctdb
, &generation
);
4678 fprintf(stderr
, "Failed to get current generation\n");
4682 count
= list_of_active_nodes(nodemap
, CTDB_UNKNOWN_PNN
, mem_ctx
,
4688 ctdb_req_control_db_freeze(&request
, db_id
);
4689 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4690 ctdb
->client
, pnn_list
, count
,
4691 TIMEOUT(), &request
, NULL
, NULL
);
4696 wipedb
.db_id
= db_id
;
4697 wipedb
.tid
= generation
;
4699 ctdb_req_control_db_transaction_start(&request
, &wipedb
);
4700 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4701 pnn_list
, count
, TIMEOUT(),
4702 &request
, NULL
, NULL
);
4707 ctdb_req_control_wipe_database(&request
, &wipedb
);
4708 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4709 pnn_list
, count
, TIMEOUT(),
4710 &request
, NULL
, NULL
);
4715 ctdb_req_control_db_set_healthy(&request
, db_id
);
4716 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4717 pnn_list
, count
, TIMEOUT(),
4718 &request
, NULL
, NULL
);
4723 ctdb_req_control_db_transaction_commit(&request
, &wipedb
);
4724 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4725 pnn_list
, count
, TIMEOUT(),
4726 &request
, NULL
, NULL
);
4731 ctdb_req_control_db_thaw(&request
, db_id
);
4732 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
,
4733 ctdb
->client
, pnn_list
, count
,
4734 TIMEOUT(), &request
, NULL
, NULL
);
4739 printf("Database %s wiped\n", db_name
);
4744 ctdb_ctrl_set_recmode(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4745 ctdb
->pnn
, TIMEOUT(), CTDB_RECOVERY_ACTIVE
);
4749 static int control_leader(TALLOC_CTX
*mem_ctx
,
4750 struct ctdb_context
*ctdb
,
4757 ret
= get_leader(mem_ctx
, ctdb
, &leader
);
4767 static int control_event(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4768 int argc
, const char **argv
)
4770 char *t
, *event_helper
= NULL
;
4772 t
= getenv("CTDB_EVENT_HELPER");
4774 event_helper
= talloc_strdup(mem_ctx
, t
);
4776 event_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb-event",
4777 CTDB_HELPER_BINDIR
);
4780 if (event_helper
== NULL
) {
4781 fprintf(stderr
, "Unable to set event daemon helper\n");
4785 return run_helper(mem_ctx
, "event daemon helper", event_helper
,
4789 static int control_scriptstatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4790 int argc
, const char **argv
)
4792 const char *new_argv
[4];
4795 usage("scriptstatus");
4798 new_argv
[0] = "status";
4799 new_argv
[1] = "legacy";
4800 new_argv
[2] = (argc
== 0) ? "monitor" : argv
[0];
4803 (void) control_event(mem_ctx
, ctdb
, 3, new_argv
);
4807 static int control_natgw(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4808 int argc
, const char **argv
)
4810 char *t
, *natgw_helper
= NULL
;
4816 t
= getenv("CTDB_NATGW_HELPER");
4818 natgw_helper
= talloc_strdup(mem_ctx
, t
);
4820 natgw_helper
= talloc_asprintf(mem_ctx
, "%s/ctdb_natgw",
4821 CTDB_HELPER_BINDIR
);
4824 if (natgw_helper
== NULL
) {
4825 fprintf(stderr
, "Unable to set NAT gateway helper\n");
4829 return run_helper(mem_ctx
, "NAT gateway helper", natgw_helper
,
4834 * Find the PNN of the current node
4835 * discover the pnn by loading the nodes file and try to bind
4836 * to all addresses one at a time until the ip address is found.
4838 static bool find_node_xpnn(TALLOC_CTX
*mem_ctx
, uint32_t *pnn
)
4840 struct ctdb_node_map
*nodemap
;
4843 nodemap
= read_nodes_file(mem_ctx
, CTDB_UNKNOWN_PNN
);
4844 if (nodemap
== NULL
) {
4848 for (i
=0; i
<nodemap
->num
; i
++) {
4849 if (nodemap
->node
[i
].flags
& NODE_FLAGS_DELETED
) {
4852 if (ctdb_sys_have_ip(&nodemap
->node
[i
].addr
)) {
4854 *pnn
= nodemap
->node
[i
].pnn
;
4856 talloc_free(nodemap
);
4861 fprintf(stderr
, "Failed to detect PNN of the current node.\n");
4862 talloc_free(nodemap
);
4866 static int control_getreclock(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4867 int argc
, const char **argv
)
4869 const char *reclock
;
4873 usage("getreclock");
4876 ret
= ctdb_ctrl_get_reclock_file(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4877 ctdb
->cmd_pnn
, TIMEOUT(), &reclock
);
4882 if (reclock
!= NULL
) {
4883 printf("%s\n", reclock
);
4889 static int control_setlmasterrole(TALLOC_CTX
*mem_ctx
,
4890 struct ctdb_context
*ctdb
,
4891 int argc
, const char **argv
)
4893 uint32_t lmasterrole
= 0;
4897 usage("setlmasterrole");
4900 if (strcmp(argv
[0], "on") == 0) {
4902 } else if (strcmp(argv
[0], "off") == 0) {
4905 usage("setlmasterrole");
4908 ret
= ctdb_ctrl_set_lmasterrole(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4909 ctdb
->cmd_pnn
, TIMEOUT(), lmasterrole
);
4917 static int control_setleaderrole(TALLOC_CTX
*mem_ctx
,
4918 struct ctdb_context
*ctdb
,
4922 uint32_t leaderrole
= 0;
4926 usage("setleaderrole");
4929 if (strcmp(argv
[0], "on") == 0) {
4931 } else if (strcmp(argv
[0], "off") == 0) {
4934 usage("setleaderrole");
4937 ret
= ctdb_ctrl_set_recmasterrole(mem_ctx
,
4950 static int control_setdbreadonly(TALLOC_CTX
*mem_ctx
,
4951 struct ctdb_context
*ctdb
,
4952 int argc
, const char **argv
)
4959 usage("setdbreadonly");
4962 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4966 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4967 fprintf(stderr
, "READONLY can be set only on volatile DB\n");
4971 ret
= ctdb_ctrl_set_db_readonly(mem_ctx
, ctdb
->ev
, ctdb
->client
,
4972 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
4980 static int control_setdbsticky(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
4981 int argc
, const char **argv
)
4988 usage("setdbsticky");
4991 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, NULL
, &db_flags
)) {
4995 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
4996 fprintf(stderr
, "STICKY can be set only on volatile DB\n");
5000 ret
= ctdb_ctrl_set_db_sticky(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5001 ctdb
->cmd_pnn
, TIMEOUT(), db_id
);
5009 static int control_pfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5010 int argc
, const char **argv
)
5012 const char *db_name
;
5013 struct ctdb_db_context
*db
;
5014 struct ctdb_transaction_handle
*h
;
5023 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5028 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5029 fprintf(stderr
, "Transactions not supported on DB %s\n",
5034 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5037 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5041 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5043 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5047 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5048 TIMEOUT(), db
, true, &h
);
5050 fprintf(stderr
, "Failed to start transaction on db %s\n",
5055 ret
= ctdb_transaction_fetch_record(h
, key
, mem_ctx
, &data
);
5057 fprintf(stderr
, "Failed to read record for key %s\n",
5059 ctdb_transaction_cancel(h
);
5063 printf("%.*s\n", (int)data
.dsize
, data
.dptr
);
5065 ctdb_transaction_cancel(h
);
5069 static int control_pstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5070 int argc
, const char **argv
)
5072 const char *db_name
;
5073 struct ctdb_db_context
*db
;
5074 struct ctdb_transaction_handle
*h
;
5083 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5088 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5089 fprintf(stderr
, "Transactions not supported on DB %s\n",
5094 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5097 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5101 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5103 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5107 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5109 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5113 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5114 TIMEOUT(), db
, false, &h
);
5116 fprintf(stderr
, "Failed to start transaction on db %s\n",
5121 ret
= ctdb_transaction_store_record(h
, key
, data
);
5123 fprintf(stderr
, "Failed to store record for key %s\n",
5125 ctdb_transaction_cancel(h
);
5129 ret
= ctdb_transaction_commit(h
);
5131 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5133 ctdb_transaction_cancel(h
);
5140 static int control_pdelete(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5141 int argc
, const char **argv
)
5143 const char *db_name
;
5144 struct ctdb_db_context
*db
;
5145 struct ctdb_transaction_handle
*h
;
5154 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5159 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5160 fprintf(stderr
, "Transactions not supported on DB %s\n",
5165 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5168 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5172 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5174 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5178 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5179 TIMEOUT(), db
, false, &h
);
5181 fprintf(stderr
, "Failed to start transaction on db %s\n",
5186 ret
= ctdb_transaction_delete_record(h
, key
);
5188 fprintf(stderr
, "Failed to delete record for key %s\n",
5190 ctdb_transaction_cancel(h
);
5194 ret
= ctdb_transaction_commit(h
);
5196 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5198 ctdb_transaction_cancel(h
);
5205 static int ptrans_parse_string(TALLOC_CTX
*mem_ctx
, const char **ptr
, TDB_DATA
*data
)
5213 /* Skip whitespace */
5214 n
= strspn(*ptr
, " \t");
5218 /* Quoted ASCII string - no wide characters! */
5220 n
= strcspn(t
, "\"");
5223 ret
= str_to_data(t
, n
, mem_ctx
, data
);
5230 fprintf(stderr
, "Unmatched \" in input %s\n", *ptr
);
5234 fprintf(stderr
, "Unsupported input format in %s\n", *ptr
);
5241 #define MAX_LINE_SIZE 1024
5243 static bool ptrans_get_key_value(TALLOC_CTX
*mem_ctx
, FILE *file
,
5244 TDB_DATA
*key
, TDB_DATA
*value
)
5246 char line
[MAX_LINE_SIZE
]; /* FIXME: make this more flexible? */
5250 ptr
= fgets(line
, MAX_LINE_SIZE
, file
);
5256 ret
= ptrans_parse_string(mem_ctx
, &ptr
, key
);
5257 if (ret
!= 0 || ptr
== NULL
|| key
->dptr
== NULL
) {
5258 /* Line Ignored but not EOF */
5264 ret
= ptrans_parse_string(mem_ctx
, &ptr
, value
);
5266 /* Line Ignored but not EOF */
5267 talloc_free(key
->dptr
);
5275 static int control_ptrans(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5276 int argc
, const char **argv
)
5278 const char *db_name
;
5279 struct ctdb_db_context
*db
;
5280 struct ctdb_transaction_handle
*h
;
5283 TDB_DATA key
= tdb_null
, value
= tdb_null
;
5286 if (argc
< 1 || argc
> 2) {
5290 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5295 (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
))) {
5296 fprintf(stderr
, "Transactions not supported on DB %s\n",
5302 file
= fopen(argv
[1], "r");
5304 fprintf(stderr
, "Failed to open file %s\n", argv
[1]);
5311 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5314 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5318 ret
= ctdb_transaction_start(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5319 TIMEOUT(), db
, false, &h
);
5321 fprintf(stderr
, "Failed to start transaction on db %s\n",
5326 while (ptrans_get_key_value(mem_ctx
, file
, &key
, &value
)) {
5327 if (key
.dsize
!= 0) {
5328 ret
= ctdb_transaction_store_record(h
, key
, value
);
5330 fprintf(stderr
, "Failed to store record\n");
5331 ctdb_transaction_cancel(h
);
5334 talloc_free(key
.dptr
);
5335 talloc_free(value
.dptr
);
5339 ret
= ctdb_transaction_commit(h
);
5341 fprintf(stderr
, "Failed to commit transaction on db %s\n",
5343 ctdb_transaction_cancel(h
);
5347 if (file
!= stdin
) {
5353 static int control_tfetch(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5354 int argc
, const char **argv
)
5356 struct tdb_context
*tdb
;
5358 struct ctdb_ltdb_header header
;
5361 if (argc
< 2 || argc
> 3) {
5365 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5367 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5371 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5373 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5378 data
= tdb_fetch(tdb
, key
);
5379 if (data
.dptr
== NULL
) {
5380 fprintf(stderr
, "No record for key %s\n", argv
[1]);
5385 if (data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
5386 fprintf(stderr
, "Invalid record for key %s\n", argv
[1]);
5397 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
5399 fprintf(stderr
, "Failed to open output file %s\n",
5404 nwritten
= sys_write(fd
, data
.dptr
, data
.dsize
);
5405 if (nwritten
== -1 ||
5406 (size_t)nwritten
!= data
.dsize
) {
5407 fprintf(stderr
, "Failed to write record to file\n");
5416 ret
= ctdb_ltdb_header_extract(&data
, &header
);
5418 fprintf(stderr
, "Failed to parse header from data\n");
5422 dump_ltdb_header(&header
);
5423 dump_tdb_data("data", data
);
5428 static int control_tstore(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5429 int argc
, const char **argv
)
5431 struct tdb_context
*tdb
;
5432 TDB_DATA key
, data
[2], value
;
5433 struct ctdb_ltdb_header header
;
5434 uint8_t header_buf
[sizeof(struct ctdb_ltdb_header
)];
5438 if (argc
< 3 || argc
> 5) {
5442 tdb
= tdb_open(argv
[0], 0, 0, O_RDWR
, 0);
5444 fprintf(stderr
, "Failed to open TDB file %s\n", argv
[0]);
5448 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5450 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5455 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &value
);
5457 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5462 ZERO_STRUCT(header
);
5465 header
.rsn
= (uint64_t)smb_strtoull(argv
[3],
5475 header
.dmaster
= (uint32_t)atol(argv
[4]);
5478 header
.flags
= (uint32_t)atol(argv
[5]);
5481 ctdb_ltdb_header_push(&header
, header_buf
, &np
);
5484 data
[0].dptr
= header_buf
;
5486 data
[1].dsize
= value
.dsize
;
5487 data
[1].dptr
= value
.dptr
;
5489 ret
= tdb_storev(tdb
, key
, data
, 2, TDB_REPLACE
);
5491 fprintf(stderr
, "Failed to write record %s to file %s\n",
5500 static int control_readkey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5501 int argc
, const char **argv
)
5503 const char *db_name
;
5504 struct ctdb_db_context
*db
;
5505 struct ctdb_record_handle
*h
;
5508 bool readonly
= false;
5511 if (argc
< 2 || argc
> 3) {
5516 if (strcmp(argv
[2], "readonly") == 0) {
5523 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5527 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5528 fprintf(stderr
, "DB %s is not a volatile database\n",
5533 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5536 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5540 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5542 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5546 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5547 db
, key
, readonly
, &h
, NULL
, &data
);
5549 fprintf(stderr
, "Failed to read record for key %s\n",
5552 printf("Data: size:%zu ptr:[%.*s]\n", data
.dsize
,
5553 (int)data
.dsize
, data
.dptr
);
5560 static int control_writekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5561 int argc
, const char **argv
)
5563 const char *db_name
;
5564 struct ctdb_db_context
*db
;
5565 struct ctdb_record_handle
*h
;
5574 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5578 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5579 fprintf(stderr
, "DB %s is not a volatile database\n",
5584 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5587 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5591 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5593 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5597 ret
= str_to_data(argv
[2], strlen(argv
[2]), mem_ctx
, &data
);
5599 fprintf(stderr
, "Failed to parse value %s\n", argv
[2]);
5603 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5604 db
, key
, false, &h
, NULL
, NULL
);
5606 fprintf(stderr
, "Failed to lock record for key %s\n", argv
[0]);
5610 ret
= ctdb_store_record(h
, data
);
5612 fprintf(stderr
, "Failed to store record for key %s\n",
5620 static int control_deletekey(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5621 int argc
, const char **argv
)
5623 const char *db_name
;
5624 struct ctdb_db_context
*db
;
5625 struct ctdb_record_handle
*h
;
5634 if (! db_exists(mem_ctx
, ctdb
, argv
[0], NULL
, &db_name
, &db_flags
)) {
5638 if (db_flags
& (CTDB_DB_FLAGS_PERSISTENT
| CTDB_DB_FLAGS_REPLICATED
)) {
5639 fprintf(stderr
, "DB %s is not a volatile database\n",
5644 ret
= ctdb_attach(ctdb
->ev
, ctdb
->client
, TIMEOUT(), db_name
,
5647 fprintf(stderr
, "Failed to attach to DB %s\n", db_name
);
5651 ret
= str_to_data(argv
[1], strlen(argv
[1]), mem_ctx
, &key
);
5653 fprintf(stderr
, "Failed to parse key %s\n", argv
[1]);
5657 ret
= ctdb_fetch_lock(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5658 db
, key
, false, &h
, NULL
, &data
);
5660 fprintf(stderr
, "Failed to fetch record for key %s\n",
5665 ret
= ctdb_delete_record(h
);
5667 fprintf(stderr
, "Failed to delete record for key %s\n",
5675 static int control_checktcpport(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5676 int argc
, const char **argv
)
5678 struct sockaddr_in sin
;
5684 usage("chktcpport");
5687 port
= atoi(argv
[0]);
5689 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
5691 fprintf(stderr
, "Failed to open local socket\n");
5695 v
= fcntl(s
, F_GETFL
, 0);
5696 if (v
== -1 || fcntl(s
, F_SETFL
, v
| O_NONBLOCK
)) {
5697 fprintf(stderr
, "Unable to set socket non-blocking\n");
5702 bzero(&sin
, sizeof(sin
));
5703 sin
.sin_family
= AF_INET
;
5704 sin
.sin_port
= htons(port
);
5705 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
5708 fprintf(stderr
, "Failed to bind to TCP port %u\n", port
);
5715 static int control_getdbseqnum(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5716 int argc
, const char **argv
)
5719 const char *db_name
;
5724 usage("getdbseqnum");
5727 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5731 ret
= ctdb_ctrl_get_db_seqnum(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5732 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5735 fprintf(stderr
, "Failed to get sequence number for DB %s\n",
5740 printf("0x%"PRIx64
"\n", seqnum
);
5744 static int control_nodestatus(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5745 int argc
, const char **argv
)
5747 const char *nodestring
= NULL
;
5748 struct ctdb_node_map
*nodemap_in
;
5749 struct ctdb_node_map
*nodemap
;
5752 bool print_hdr
= false;
5755 usage("nodestatus");
5759 nodestring
= argv
[0];
5760 if (strcmp(nodestring
, "all") == 0) {
5765 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap_in
)) {
5769 nodemap
= get_nodemap_unknown(mem_ctx
, ctdb
, nodemap_in
);
5770 if (nodemap
== NULL
) {
5774 if (options
.machinereadable
) {
5775 print_nodemap_machine(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
);
5777 print_nodemap(mem_ctx
, ctdb
, nodemap
, ctdb
->cmd_pnn
, print_hdr
);
5781 for (i
=0; i
<nodemap
->num
; i
++) {
5782 uint32_t flags
= nodemap
->node
[i
].flags
;
5784 if ((flags
& NODE_FLAGS_DELETED
) != 0) {
5797 } db_stats_fields
[] = {
5798 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5799 DBSTATISTICS_FIELD(db_ro_delegations
),
5800 DBSTATISTICS_FIELD(db_ro_revokes
),
5801 DBSTATISTICS_FIELD(locks
.num_calls
),
5802 DBSTATISTICS_FIELD(locks
.num_current
),
5803 DBSTATISTICS_FIELD(locks
.num_pending
),
5804 DBSTATISTICS_FIELD(locks
.num_failed
),
5807 static void print_dbstatistics(const char *db_name
,
5808 struct ctdb_db_statistics
*s
)
5811 const char *prefix
= NULL
;
5814 printf("DB Statistics %s\n", db_name
);
5816 for (i
=0; i
<ARRAY_SIZE(db_stats_fields
); i
++) {
5817 if (strchr(db_stats_fields
[i
].name
, '.') != NULL
) {
5818 preflen
= strcspn(db_stats_fields
[i
].name
, ".") + 1;
5820 strncmp(prefix
, db_stats_fields
[i
].name
, preflen
) != 0) {
5821 prefix
= db_stats_fields
[i
].name
;
5822 printf(" %*.*s\n", preflen
-1, preflen
-1,
5823 db_stats_fields
[i
].name
);
5828 printf(" %*s%-22s%*s%10u\n", preflen
? 4 : 0, "",
5829 db_stats_fields
[i
].name
+preflen
, preflen
? 0 : 4, "",
5830 *(uint32_t *)(db_stats_fields
[i
].offset
+(uint8_t *)s
));
5833 printf(" hop_count_buckets:");
5834 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5835 printf(" %d", s
->hop_count_bucket
[i
]);
5839 printf(" lock_buckets:");
5840 for (i
=0; i
<MAX_COUNT_BUCKETS
; i
++) {
5841 printf(" %d", s
->locks
.buckets
[i
]);
5845 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5846 "locks_latency MIN/AVG/MAX",
5847 s
->locks
.latency
.min
, LATENCY_AVG(s
->locks
.latency
),
5848 s
->locks
.latency
.max
, s
->locks
.latency
.num
);
5850 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5851 "vacuum_latency MIN/AVG/MAX",
5852 s
->vacuum
.latency
.min
, LATENCY_AVG(s
->vacuum
.latency
),
5853 s
->vacuum
.latency
.max
, s
->vacuum
.latency
.num
);
5855 printf(" Num Hot Keys: %d\n", s
->num_hot_keys
);
5856 for (i
=0; i
<s
->num_hot_keys
; i
++) {
5858 printf(" Count:%d Key:", s
->hot_keys
[i
].count
);
5859 for (j
=0; j
<s
->hot_keys
[i
].key
.dsize
; j
++) {
5860 printf("%02x", s
->hot_keys
[i
].key
.dptr
[j
] & 0xff);
5866 static int control_dbstatistics(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
5867 int argc
, const char **argv
)
5870 const char *db_name
;
5871 struct ctdb_db_statistics
*dbstats
;
5875 usage("dbstatistics");
5878 if (! db_exists(mem_ctx
, ctdb
, argv
[0], &db_id
, &db_name
, NULL
)) {
5882 ret
= ctdb_ctrl_get_db_statistics(mem_ctx
, ctdb
->ev
, ctdb
->client
,
5883 ctdb
->cmd_pnn
, TIMEOUT(), db_id
,
5886 fprintf(stderr
, "Failed to get statistics for DB %s\n",
5891 print_dbstatistics(db_name
, dbstats
);
5895 struct disable_takeover_runs_state
{
5897 unsigned int node_count
;
5903 static void disable_takeover_run_handler(uint64_t srvid
, TDB_DATA data
,
5906 struct disable_takeover_runs_state
*state
=
5907 (struct disable_takeover_runs_state
*)private_data
;
5911 if (data
.dsize
!= sizeof(int)) {
5916 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5917 ret
= *(int *)data
.dptr
;
5919 state
->status
= ret
;
5923 for (i
=0; i
<state
->node_count
; i
++) {
5924 if (state
->pnn_list
[i
] == (uint32_t)ret
) {
5925 state
->reply
[i
] = true;
5931 for (i
=0; i
<state
->node_count
; i
++) {
5932 if (! state
->reply
[i
]) {
5933 state
->done
= false;
5939 static int disable_takeover_runs(TALLOC_CTX
*mem_ctx
,
5940 struct ctdb_context
*ctdb
, uint32_t timeout
,
5941 uint32_t *pnn_list
, int count
)
5943 struct ctdb_disable_message disable
= { 0 };
5944 struct disable_takeover_runs_state state
;
5947 disable
.pnn
= ctdb
->pnn
;
5948 disable
.srvid
= next_srvid(ctdb
);
5949 disable
.timeout
= timeout
;
5951 state
.pnn_list
= pnn_list
;
5952 state
.node_count
= count
;
5955 state
.reply
= talloc_zero_array(mem_ctx
, bool, count
);
5956 if (state
.reply
== NULL
) {
5960 ret
= ctdb_client_set_message_handler(ctdb
->ev
, ctdb
->client
,
5962 disable_takeover_run_handler
,
5968 for (i
=0; i
<count
; i
++) {
5969 ret
= ctdb_message_disable_takeover_runs(mem_ctx
, ctdb
->ev
,
5978 ret
= ctdb_client_wait_timeout(ctdb
->ev
, &state
.done
, TIMEOUT());
5980 fprintf(stderr
, "Timed out waiting to disable takeover runs\n");
5982 ret
= (state
.status
>= 0 ? 0 : 1);
5986 ctdb_client_remove_message_handler(ctdb
->ev
, ctdb
->client
,
5987 disable
.srvid
, &state
);
5991 static int send_ipreallocated_control_to_nodes(TALLOC_CTX
*mem_ctx
,
5992 struct ctdb_context
*ctdb
,
5996 struct ctdb_req_control request
;
5999 ctdb_req_control_ipreallocated(&request
);
6000 ret
= ctdb_client_control_multi(mem_ctx
,
6007 NULL
, /* perr_list */
6010 fprintf(stderr
, "Failed to send ipreallocated\n");
6017 static int control_reloadips(TALLOC_CTX
*mem_ctx
, struct ctdb_context
*ctdb
,
6018 int argc
, const char **argv
)
6020 const char *nodestring
= NULL
;
6021 struct ctdb_node_map
*nodemap
, *nodemap2
;
6022 struct ctdb_req_control request
;
6023 uint32_t *pnn_list
, *pnn_list2
;
6024 int ret
, count
, count2
;
6031 nodestring
= argv
[0];
6034 nodemap
= get_nodemap(ctdb
, false);
6035 if (nodemap
== NULL
) {
6039 if (! parse_nodestring(mem_ctx
, ctdb
, nodestring
, &nodemap2
)) {
6043 count
= list_of_connected_nodes(nodemap
, CTDB_UNKNOWN_PNN
,
6044 mem_ctx
, &pnn_list
);
6046 fprintf(stderr
, "Memory allocation error\n");
6050 count2
= list_of_active_nodes(nodemap2
, CTDB_UNKNOWN_PNN
,
6051 mem_ctx
, &pnn_list2
);
6053 fprintf(stderr
, "Memory allocation error\n");
6057 /* Disable takeover runs on all connected nodes. A reply
6058 * indicating success is needed from each node so all nodes
6059 * will need to be active.
6061 * A check could be added to not allow reloading of IPs when
6062 * there are disconnected nodes. However, this should
6063 * probably be left up to the administrator.
6065 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 2*options
.timelimit
,
6068 fprintf(stderr
, "Failed to disable takeover runs\n");
6072 /* Now tell all the desired nodes to reload their public IPs.
6073 * Keep trying this until it succeeds. This assumes all
6074 * failures are transient, which might not be true...
6076 ctdb_req_control_reload_public_ips(&request
);
6077 ret
= ctdb_client_control_multi(mem_ctx
, ctdb
->ev
, ctdb
->client
,
6078 pnn_list2
, count2
, TIMEOUT(),
6079 &request
, NULL
, NULL
);
6081 fprintf(stderr
, "Failed to reload IPs on some nodes.\n");
6084 /* It isn't strictly necessary to wait until takeover runs are
6085 * re-enabled but doing so can't hurt.
6087 ret
= disable_takeover_runs(mem_ctx
, ctdb
, 0, pnn_list
, count
);
6089 fprintf(stderr
, "Failed to enable takeover runs\n");
6093 return ipreallocate(mem_ctx
, ctdb
);
6097 static const struct ctdb_cmd
{
6099 int (*fn
)(TALLOC_CTX
*, struct ctdb_context
*, int, const char **);
6100 bool without_daemon
; /* can be run without daemon running ? */
6101 bool remote
; /* can be run on remote nodes */
6104 } ctdb_commands
[] = {
6105 { "version", control_version
, true, false,
6106 "show version of ctdb", NULL
},
6107 { "status", control_status
, false, true,
6108 "show node status", NULL
},
6109 { "uptime", control_uptime
, false, true,
6110 "show node uptime", NULL
},
6111 { "ping", control_ping
, false, true,
6112 "ping a node", NULL
},
6113 { "runstate", control_runstate
, false, true,
6114 "get/check runstate of a node",
6115 "[setup|first_recovery|startup|running]" },
6116 { "getvar", control_getvar
, false, true,
6117 "get a tunable variable", "<name>" },
6118 { "setvar", control_setvar
, false, true,
6119 "set a tunable variable", "<name> <value>" },
6120 { "listvars", control_listvars
, false, true,
6121 "list tunable variables", NULL
},
6122 { "statistics", control_statistics
, false, true,
6123 "show ctdb statistics", NULL
},
6124 { "statisticsreset", control_statistics_reset
, false, true,
6125 "reset ctdb statistics", NULL
},
6126 { "stats", control_stats
, false, true,
6127 "show rolling statistics", "[count]" },
6128 { "ip", control_ip
, false, true,
6129 "show public ips", "[all]" },
6130 { "ipinfo", control_ipinfo
, false, true,
6131 "show public ip details", "<ip>" },
6132 { "ifaces", control_ifaces
, false, true,
6133 "show interfaces", NULL
},
6134 { "setifacelink", control_setifacelink
, false, true,
6135 "set interface link status", "<iface> up|down" },
6136 { "process-exists", control_process_exists
, false, true,
6137 "check if a process exists on a node", "<pid> [<srvid>]" },
6138 { "getdbmap", control_getdbmap
, false, true,
6139 "show attached databases", NULL
},
6140 { "getdbstatus", control_getdbstatus
, false, true,
6141 "show database status", "<dbname|dbid>" },
6142 { "catdb", control_catdb
, false, false,
6143 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6144 { "cattdb", control_cattdb
, false, false,
6145 "dump local ctdb database", "<dbname|dbid>" },
6146 { "getcapabilities", control_getcapabilities
, false, true,
6147 "show node capabilities", NULL
},
6148 { "pnn", control_pnn
, false, false,
6149 "show the pnn of the current node", NULL
},
6150 { "lvs", control_lvs
, false, false,
6151 "show lvs configuration", "leader|list|status" },
6152 { "setdebug", control_setdebug
, false, true,
6153 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6154 { "getdebug", control_getdebug
, false, true,
6155 "get debug level", NULL
},
6156 { "attach", control_attach
, false, false,
6157 "attach a database", "<dbname> [persistent|replicated]" },
6158 { "detach", control_detach
, false, false,
6159 "detach database(s)", "<dbname|dbid> ..." },
6160 { "dumpmemory", control_dumpmemory
, false, true,
6161 "dump ctdbd memory map", NULL
},
6162 { "rddumpmemory", control_rddumpmemory
, false, true,
6163 "dump recoverd memory map", NULL
},
6164 { "getpid", control_getpid
, false, true,
6165 "get ctdbd process ID", NULL
},
6166 { "disable", control_disable
, false, true,
6167 "disable a node", NULL
},
6168 { "enable", control_enable
, false, true,
6169 "enable a node", NULL
},
6170 { "stop", control_stop
, false, true,
6171 "stop a node", NULL
},
6172 { "continue", control_continue
, false, true,
6173 "continue a stopped node", NULL
},
6174 { "ban", control_ban
, false, true,
6175 "ban a node", "<bantime>"},
6176 { "unban", control_unban
, false, true,
6177 "unban a node", NULL
},
6178 { "shutdown", control_shutdown
, false, true,
6179 "shutdown ctdb daemon", NULL
},
6180 { "recover", control_recover
, false, true,
6181 "force recovery", NULL
},
6182 { "sync", control_ipreallocate
, false, true,
6183 "run ip reallocation (deprecated)", NULL
},
6184 { "ipreallocate", control_ipreallocate
, false, true,
6185 "run ip reallocation", NULL
},
6186 { "gratarp", control_gratarp
, false, true,
6187 "send a gratuitous arp", "<ip> <interface>" },
6188 { "tickle", control_tickle
, true, false,
6189 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6190 { "gettickles", control_gettickles
, false, true,
6191 "get the list of tickles", "<ip> [<port>]" },
6192 { "addtickle", control_addtickle
, false, true,
6193 "add a tickle", "<ip>:<port> <ip>:<port>" },
6194 { "deltickle", control_deltickle
, false, true,
6195 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6196 { "listnodes", control_listnodes
, true, true,
6197 "list nodes in the cluster", NULL
},
6198 { "reloadnodes", control_reloadnodes
, false, false,
6199 "reload the nodes file all nodes", NULL
},
6200 { "moveip", control_moveip
, false, false,
6201 "move an ip address to another node", "<ip> <node>" },
6202 { "addip", control_addip
, false, true,
6203 "add an ip address to a node", "<ip/mask> <iface>" },
6204 { "delip", control_delip
, false, true,
6205 "delete an ip address from a node", "<ip>" },
6206 { "backupdb", control_backupdb
, false, false,
6207 "backup a database into a file", "<dbname|dbid> <file>" },
6208 { "restoredb", control_restoredb
, false, false,
6209 "restore a database from a file", "<file> [dbname]" },
6210 { "dumpdbbackup", control_dumpdbbackup
, true, false,
6211 "dump database from a backup file", "<file>" },
6212 { "wipedb", control_wipedb
, false, false,
6213 "wipe the contents of a database.", "<dbname|dbid>"},
6214 { "leader", control_leader
, false, true,
6215 "show the pnn of the leader", NULL
},
6216 { "event", control_event
, true, false,
6217 "event and event script commands", NULL
},
6218 { "scriptstatus", control_scriptstatus
, true, false,
6219 "show event script status",
6220 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6221 { "natgw", control_natgw
, false, false,
6222 "show natgw configuration", "leader|list|status" },
6223 { "getreclock", control_getreclock
, false, true,
6224 "get recovery lock file", NULL
},
6225 { "setlmasterrole", control_setlmasterrole
, false, true,
6226 "set LMASTER role", "on|off" },
6227 { "setleaderrole", control_setleaderrole
, false, true,
6228 "set LEADER role", "on|off"},
6229 { "setdbreadonly", control_setdbreadonly
, false, true,
6230 "enable readonly records", "<dbname|dbid>" },
6231 { "setdbsticky", control_setdbsticky
, false, true,
6232 "enable sticky records", "<dbname|dbid>"},
6233 { "pfetch", control_pfetch
, false, false,
6234 "fetch record from persistent database", "<dbname|dbid> <key>" },
6235 { "pstore", control_pstore
, false, false,
6236 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6237 { "pdelete", control_pdelete
, false, false,
6238 "delete record from persistent database", "<dbname|dbid> <key>" },
6239 { "ptrans", control_ptrans
, false, false,
6240 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6241 { "tfetch", control_tfetch
, false, true,
6242 "fetch a record", "<tdb-file> <key> [<file>]" },
6243 { "tstore", control_tstore
, false, true,
6244 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6245 { "readkey", control_readkey
, false, false,
6246 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6247 { "writekey", control_writekey
, false, false,
6248 "write value for a database key", "<dbname|dbid> <key> <value>" },
6249 { "deletekey", control_deletekey
, false, false,
6250 "delete a database key", "<dbname|dbid> <key>" },
6251 { "checktcpport", control_checktcpport
, true, false,
6252 "check if a service is bound to a specific tcp port or not", "<port>" },
6253 { "getdbseqnum", control_getdbseqnum
, false, false,
6254 "get database sequence number", "<dbname|dbid>" },
6255 { "nodestatus", control_nodestatus
, false, true,
6256 "show and return node status", "[all|<pnn-list>]" },
6257 { "dbstatistics", control_dbstatistics
, false, true,
6258 "show database statistics", "<dbname|dbid>" },
6259 { "reloadips", control_reloadips
, false, false,
6260 "reload the public addresses file", "[all|<pnn-list>]" },
6263 static const struct ctdb_cmd
*match_command(const char *command
)
6265 const struct ctdb_cmd
*cmd
;
6268 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6269 cmd
= &ctdb_commands
[i
];
6270 if (strcmp(command
, cmd
->name
) == 0) {
6280 * Show usage message
6282 static void usage_full(void)
6286 poptPrintHelp(pc
, stdout
, 0);
6287 printf("\nCommands:\n");
6288 for (i
=0; i
<ARRAY_SIZE(ctdb_commands
); i
++) {
6289 printf(" %-15s %-27s %s\n",
6290 ctdb_commands
[i
].name
,
6291 ctdb_commands
[i
].args
? ctdb_commands
[i
].args
: "",
6292 ctdb_commands
[i
].msg
);
6296 static void usage(const char *command
)
6298 const struct ctdb_cmd
*cmd
;
6300 if (command
== NULL
) {
6305 cmd
= match_command(command
);
6309 poptPrintUsage(pc
, stdout
, 0);
6310 printf("\nCommands:\n");
6311 printf(" %-15s %-27s %s\n",
6312 cmd
->name
, cmd
->args
? cmd
->args
: "", cmd
->msg
);
6318 struct poptOption cmdline_options
[] = {
6321 .longName
= "debug",
6323 .argInfo
= POPT_ARG_STRING
,
6324 .arg
= &options
.debuglevelstr
,
6326 .descrip
= "debug level",
6329 .longName
= "timelimit",
6331 .argInfo
= POPT_ARG_INT
,
6332 .arg
= &options
.timelimit
,
6334 .descrip
= "timelimit (in seconds)",
6339 .argInfo
= POPT_ARG_INT
,
6340 .arg
= &options
.pnn
,
6342 .descrip
= "node specification - integer",
6347 .argInfo
= POPT_ARG_NONE
,
6348 .arg
= &options
.machinereadable
,
6350 .descrip
= "enable machine readable output",
6353 .longName
= "separator",
6355 .argInfo
= POPT_ARG_STRING
,
6356 .arg
= &options
.sep
,
6358 .descrip
= "specify separator for machine readable output",
6359 .argDescrip
= "CHAR",
6363 .argInfo
= POPT_ARG_NONE
,
6364 .arg
= &options
.machineparsable
,
6366 .descrip
= "enable machine parsable output with separator |",
6369 .longName
= "verbose",
6371 .argInfo
= POPT_ARG_NONE
,
6372 .arg
= &options
.verbose
,
6374 .descrip
= "enable verbose output",
6377 .longName
= "maxruntime",
6379 .argInfo
= POPT_ARG_INT
,
6380 .arg
= &options
.maxruntime
,
6382 .descrip
= "die if runtime exceeds this limit (in seconds)",
6387 static int process_command(const struct ctdb_cmd
*cmd
, int argc
,
6390 TALLOC_CTX
*tmp_ctx
;
6391 struct ctdb_context
*ctdb
;
6392 const char *ctdb_socket
;
6395 uint64_t srvid_offset
;
6397 tmp_ctx
= talloc_new(NULL
);
6398 if (tmp_ctx
== NULL
) {
6399 fprintf(stderr
, "Memory allocation error\n");
6403 if (cmd
->without_daemon
) {
6404 if (options
.pnn
!= -1) {
6406 "Cannot specify node for command %s\n",
6411 ret
= cmd
->fn(tmp_ctx
, NULL
, argc
-1, argv
+1);
6412 talloc_free(tmp_ctx
);
6416 ctdb
= talloc_zero(tmp_ctx
, struct ctdb_context
);
6418 fprintf(stderr
, "Memory allocation error\n");
6422 ctdb
->ev
= tevent_context_init(ctdb
);
6423 if (ctdb
->ev
== NULL
) {
6424 fprintf(stderr
, "Failed to initialize tevent\n");
6428 ctdb_socket
= path_socket(ctdb
, "ctdbd");
6429 if (ctdb_socket
== NULL
) {
6430 fprintf(stderr
, "Memory allocation error\n");
6434 ret
= ctdb_client_init(ctdb
, ctdb
->ev
, ctdb_socket
, &ctdb
->client
);
6436 fprintf(stderr
, "Failed to connect to CTDB daemon (%s)\n",
6439 if (!find_node_xpnn(ctdb
, NULL
)) {
6440 fprintf(stderr
, "Is this node part of CTDB cluster?\n");
6445 ctdb
->pnn
= ctdb_client_pnn(ctdb
->client
);
6446 srvid_offset
= getpid() & 0xFFFF;
6447 ctdb
->srvid
= SRVID_CTDB_TOOL
| (srvid_offset
<< 16);
6449 if (options
.pnn
!= -1) {
6450 status
= verify_pnn(ctdb
, options
.pnn
);
6455 ctdb
->cmd_pnn
= options
.pnn
;
6457 ctdb
->cmd_pnn
= ctdb
->pnn
;
6460 if (! cmd
->remote
&& ctdb
->pnn
!= ctdb
->cmd_pnn
) {
6461 fprintf(stderr
, "Node cannot be specified for command %s\n",
6466 ctdb
->leader_pnn
= CTDB_UNKNOWN_PNN
;
6467 ret
= ctdb_client_set_message_handler(ctdb
->ev
,
6473 fprintf(stderr
, "Failed to setup leader handler\n");
6477 ret
= cmd
->fn(tmp_ctx
, ctdb
, argc
-1, argv
+1);
6478 talloc_free(tmp_ctx
);
6482 talloc_free(tmp_ctx
);
6486 static void signal_handler(int sig
)
6488 fprintf(stderr
, "Maximum runtime exceeded - exiting\n");
6491 static void alarm_handler(int sig
)
6493 /* Kill any child processes */
6494 signal(SIGTERM
, signal_handler
);
6500 int main(int argc
, const char *argv
[])
6503 const char **extra_argv
;
6505 const struct ctdb_cmd
*cmd
;
6506 const char *test_mode
;
6513 /* Set default options */
6514 options
.debuglevelstr
= NULL
;
6515 options
.timelimit
= 10;
6517 options
.maxruntime
= 0;
6520 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
6521 POPT_CONTEXT_KEEP_FIRST
);
6522 while ((opt
= poptGetNextOpt(pc
)) != -1) {
6523 fprintf(stderr
, "Invalid option %s: %s\n",
6524 poptBadOption(pc
, 0), poptStrerror(opt
));
6528 if (options
.maxruntime
== 0) {
6529 const char *ctdb_timeout
;
6531 ctdb_timeout
= getenv("CTDB_TIMEOUT");
6532 if (ctdb_timeout
!= NULL
) {
6533 options
.maxruntime
= smb_strtoul(ctdb_timeout
,
6539 fprintf(stderr
, "Invalid value CTDB_TIMEOUT\n");
6543 options
.maxruntime
= 120;
6547 if (options
.machineparsable
) {
6548 options
.machinereadable
= 1;
6551 /* setup the remaining options for the commands */
6553 extra_argv
= poptGetArgs(pc
);
6556 while (extra_argv
[extra_argc
]) extra_argc
++;
6559 if (extra_argc
< 1) {
6563 cmd
= match_command(extra_argv
[0]);
6565 fprintf(stderr
, "Unknown command '%s'\n", extra_argv
[0]);
6569 /* Enable logging */
6570 setup_logging("ctdb", DEBUG_STDERR
);
6571 ok
= debug_level_parse(options
.debuglevelstr
, &loglevel
);
6573 loglevel
= DEBUG_ERR
;
6575 debuglevel_set(loglevel
);
6577 /* Stop process group kill in alarm_handler() from killing tests */
6578 test_mode
= getenv("CTDB_TEST_MODE");
6579 if (test_mode
!= NULL
) {
6580 const char *have_setpgid
= getenv("CTDB_TOOL_SETPGID");
6581 if (have_setpgid
== NULL
) {
6583 setenv("CTDB_TOOL_SETPGID", "1", 1);
6587 signal(SIGALRM
, alarm_handler
);
6588 alarm(options
.maxruntime
);
6590 ret
= process_command(cmd
, extra_argc
, extra_argv
);
6595 (void)poptFreeContext(pc
);