40852b063ec56dcba68c195be8c3f5b0e4638ee4
[samba.git] / ctdb / tools / ctdb_control.c
1 /* 
2    ctdb control tool
3
4    Copyright (C) Andrew Tridgell  2007
5
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 2 of the License, or
9    (at your option) any later version.
10    
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.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "lib/events/events.h"
23 #include "system/filesys.h"
24 #include "popt.h"
25 #include "cmdline.h"
26 #include "../include/ctdb.h"
27 #include "../include/ctdb_private.h"
28 #include <arpa/inet.h>
29
30 static void usage(void);
31
32 static struct {
33         int timelimit;
34         uint32_t vnn;
35         int machinereadable;
36 } options;
37
38 #define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
39
40 /*
41   see if a process exists
42  */
43 static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv)
44 {
45         uint32_t vnn, pid;
46         int ret;
47         if (argc < 1) {
48                 usage();
49         }
50
51         if (sscanf(argv[0], "%u:%u", &vnn, &pid) != 2) {
52                 printf("Badly formed vnn:pid\n");
53                 return -1;
54         }
55
56         ret = ctdb_ctrl_process_exists(ctdb, vnn, pid);
57         if (ret == 0) {
58                 printf("%u:%u exists\n", vnn, pid);
59         } else {
60                 printf("%u:%u does not exist\n", vnn, pid);
61         }
62         return ret;
63 }
64
65 /*
66   display statistics structure
67  */
68 static void show_statistics(struct ctdb_statistics *s)
69 {
70         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
71         int i;
72         const char *prefix=NULL;
73         int preflen=0;
74         const struct {
75                 const char *name;
76                 uint32_t offset;
77         } fields[] = {
78 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
79                 STATISTICS_FIELD(num_clients),
80                 STATISTICS_FIELD(frozen),
81                 STATISTICS_FIELD(recovering),
82                 STATISTICS_FIELD(client_packets_sent),
83                 STATISTICS_FIELD(client_packets_recv),
84                 STATISTICS_FIELD(node_packets_sent),
85                 STATISTICS_FIELD(node_packets_recv),
86                 STATISTICS_FIELD(keepalive_packets_sent),
87                 STATISTICS_FIELD(keepalive_packets_recv),
88                 STATISTICS_FIELD(node.req_call),
89                 STATISTICS_FIELD(node.reply_call),
90                 STATISTICS_FIELD(node.req_dmaster),
91                 STATISTICS_FIELD(node.reply_dmaster),
92                 STATISTICS_FIELD(node.reply_error),
93                 STATISTICS_FIELD(node.req_message),
94                 STATISTICS_FIELD(node.req_control),
95                 STATISTICS_FIELD(node.reply_control),
96                 STATISTICS_FIELD(client.req_call),
97                 STATISTICS_FIELD(client.req_message),
98                 STATISTICS_FIELD(client.req_control),
99                 STATISTICS_FIELD(controls.statistics),
100                 STATISTICS_FIELD(controls.get_config),
101                 STATISTICS_FIELD(controls.ping),
102                 STATISTICS_FIELD(controls.attach),
103                 STATISTICS_FIELD(controls.set_call),
104                 STATISTICS_FIELD(controls.process_exists),
105                 STATISTICS_FIELD(controls.traverse_start),
106                 STATISTICS_FIELD(controls.traverse_all),
107                 STATISTICS_FIELD(controls.traverse_data),
108                 STATISTICS_FIELD(controls.update_seqnum),
109                 STATISTICS_FIELD(controls.enable_seqnum),
110                 STATISTICS_FIELD(controls.set_seqnum_frequency),
111                 STATISTICS_FIELD(controls.register_srvid),
112                 STATISTICS_FIELD(controls.deregister_srvid),
113                 STATISTICS_FIELD(timeouts.call),
114                 STATISTICS_FIELD(timeouts.control),
115                 STATISTICS_FIELD(timeouts.traverse),
116                 STATISTICS_FIELD(total_calls),
117                 STATISTICS_FIELD(pending_calls),
118                 STATISTICS_FIELD(lockwait_calls),
119                 STATISTICS_FIELD(pending_lockwait_calls),
120                 STATISTICS_FIELD(memory_used),
121                 STATISTICS_FIELD(max_hop_count),
122         };
123         printf("CTDB version %u\n", CTDB_VERSION);
124         for (i=0;i<ARRAY_SIZE(fields);i++) {
125                 if (strchr(fields[i].name, '.')) {
126                         preflen = strcspn(fields[i].name, ".")+1;
127                         if (!prefix || strncmp(prefix, fields[i].name, preflen) != 0) {
128                                 prefix = fields[i].name;
129                                 printf(" %*.*s\n", preflen-1, preflen-1, fields[i].name);
130                         }
131                 } else {
132                         preflen = 0;
133                 }
134                 printf(" %*s%-22s%*s%10u\n", 
135                        preflen?4:0, "",
136                        fields[i].name+preflen, 
137                        preflen?0:4, "",
138                        *(uint32_t *)(fields[i].offset+(uint8_t *)s));
139         }
140         printf(" %-30s     %.6f sec\n", "max_call_latency", s->max_call_latency);
141         printf(" %-30s     %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency);
142         talloc_free(tmp_ctx);
143 }
144
145 /*
146   display remote ctdb statistics combined from all nodes
147  */
148 static int control_statistics_all(struct ctdb_context *ctdb)
149 {
150         int ret, i;
151         struct ctdb_statistics statistics;
152         uint32_t *nodes;
153         uint32_t num_nodes;
154
155         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
156         CTDB_NO_MEMORY(ctdb, nodes);
157         
158         ZERO_STRUCT(statistics);
159
160         for (i=0;i<num_nodes;i++) {
161                 struct ctdb_statistics s1;
162                 int j;
163                 uint32_t *v1 = (uint32_t *)&s1;
164                 uint32_t *v2 = (uint32_t *)&statistics;
165                 uint32_t num_ints = 
166                         offsetof(struct ctdb_statistics, __last_counter) / sizeof(uint32_t);
167                 ret = ctdb_ctrl_statistics(ctdb, nodes[i], &s1);
168                 if (ret != 0) {
169                         printf("Unable to get statistics from node %u\n", nodes[i]);
170                         return ret;
171                 }
172                 for (j=0;j<num_ints;j++) {
173                         v2[j] += v1[j];
174                 }
175                 statistics.max_hop_count = 
176                         MAX(statistics.max_hop_count, s1.max_hop_count);
177                 statistics.max_call_latency = 
178                         MAX(statistics.max_call_latency, s1.max_call_latency);
179                 statistics.max_lockwait_latency = 
180                         MAX(statistics.max_lockwait_latency, s1.max_lockwait_latency);
181         }
182         talloc_free(nodes);
183         printf("Gathered statistics for %u nodes\n", num_nodes);
184         show_statistics(&statistics);
185         return 0;
186 }
187
188 /*
189   display remote ctdb statistics
190  */
191 static int control_statistics(struct ctdb_context *ctdb, int argc, const char **argv)
192 {
193         int ret;
194         struct ctdb_statistics statistics;
195
196         if (options.vnn == CTDB_BROADCAST_ALL) {
197                 return control_statistics_all(ctdb);
198         }
199
200         ret = ctdb_ctrl_statistics(ctdb, options.vnn, &statistics);
201         if (ret != 0) {
202                 printf("Unable to get statistics from node %u\n", options.vnn);
203                 return ret;
204         }
205         show_statistics(&statistics);
206         return 0;
207 }
208
209
210 /*
211   reset statistics on all nodes
212  */
213 static int control_statistics_reset_all(struct ctdb_context *ctdb)
214 {
215         int ret, i;
216         uint32_t *nodes;
217         uint32_t num_nodes;
218
219         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
220         CTDB_NO_MEMORY(ctdb, nodes);
221         
222         for (i=0;i<num_nodes;i++) {
223                 ret = ctdb_statistics_reset(ctdb, nodes[i]);
224                 if (ret != 0) {
225                         printf("Unable to reset statistics on node %u\n", nodes[i]);
226                         return ret;
227                 }
228         }
229         talloc_free(nodes);
230         return 0;
231 }
232
233
234 /*
235   reset remote ctdb statistics
236  */
237 static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const char **argv)
238 {
239         int ret;
240
241         if (options.vnn == CTDB_BROADCAST_ALL) {
242                 return control_statistics_reset_all(ctdb);
243         }
244
245         ret = ctdb_statistics_reset(ctdb, options.vnn);
246         if (ret != 0) {
247                 printf("Unable to reset statistics on node %u\n", options.vnn);
248                 return ret;
249         }
250         return 0;
251 }
252
253
254 /*
255   display remote ctdb status
256  */
257 static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
258 {
259         int i, ret;
260         struct ctdb_vnn_map *vnnmap=NULL;
261         struct ctdb_node_map *nodemap=NULL;
262         uint32_t recmode, recmaster;
263         uint32_t myvnn;
264
265         if (options.vnn == CTDB_BROADCAST_ALL) {
266                 uint32_t *nodes;
267                 uint32_t num_nodes;
268                 ret = 0;
269
270                 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
271                 CTDB_NO_MEMORY(ctdb, nodes);
272         
273                 for (i=0;i<num_nodes;i++) {
274                         options.vnn = nodes[i];
275                         ret |= control_status(ctdb, argc, argv);
276                 }
277                 return ret;
278         }
279
280         myvnn = ctdb_ctrl_getvnn(ctdb, TIMELIMIT(), options.vnn);
281
282         ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.vnn, ctdb, &nodemap);
283         if (ret != 0) {
284                 printf("Unable to get nodemap from node %u\n", options.vnn);
285                 return ret;
286         }
287
288         if(options.machinereadable){
289                 printf(":Node:Status:\n");
290                 for(i=0;i<nodemap->num;i++){
291                         printf(":%d:%s:%d:\n", nodemap->nodes[i].vnn,
292                                 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
293                                 !!nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED);
294                 }
295                 return 0;
296         }
297
298         printf("Number of nodes:%d\n", nodemap->num);
299         for(i=0;i<nodemap->num;i++){
300                 printf("vnn:%d %-16s %s%s\n", nodemap->nodes[i].vnn,
301                         inet_ntoa(nodemap->nodes[i].sin.sin_addr),
302                         nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED?
303                                 "CONNECTED":"UNAVAILABLE",
304                         nodemap->nodes[i].vnn == myvnn?" (THIS NODE)":"");
305         }
306
307         ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &vnnmap);
308         if (ret != 0) {
309                 printf("Unable to get vnnmap from node %u\n", options.vnn);
310                 return ret;
311         }
312         printf("Generation:%d\n",vnnmap->generation);
313         printf("Size:%d\n",vnnmap->size);
314         for(i=0;i<vnnmap->size;i++){
315                 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
316         }
317
318         ret = ctdb_ctrl_getrecmode(ctdb, TIMELIMIT(), options.vnn, &recmode);
319         if (ret != 0) {
320                 printf("Unable to get recmode from node %u\n", options.vnn);
321                 return ret;
322         }
323         printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
324
325         ret = ctdb_ctrl_getrecmaster(ctdb, TIMELIMIT(), options.vnn, &recmaster);
326         if (ret != 0) {
327                 printf("Unable to get recmaster from node %u\n", options.vnn);
328                 return ret;
329         }
330         printf("Recovery master:%d\n",recmaster);
331
332         return 0;
333 }
334
335 /*
336   display pid of a ctdb daemon
337  */
338 static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
339 {
340         uint32_t pid;
341         int ret;
342
343         ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.vnn, &pid);
344         if (ret != 0) {
345                 printf("Unable to get daemon pid from node %u\n", options.vnn);
346                 return ret;
347         }
348         printf("Pid:%d\n", pid);
349
350         return 0;
351 }
352
353 /*
354   shutdown a daemon
355  */
356 static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv)
357 {
358         int ret;
359
360         ret = ctdb_ctrl_shutdown(ctdb, timeval_current_ofs(1, 0), options.vnn);
361         if (ret != 0) {
362                 printf("Unable to shutdown node %u\n", options.vnn);
363                 return ret;
364         }
365
366         return 0;
367 }
368
369 /*
370   trigger a recovery
371  */
372 static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv)
373 {
374         int ret;
375
376         ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
377         if (ret != 0) {
378                 printf("Unable to freeze node\n");
379                 return ret;
380         }
381
382         ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.vnn, CTDB_RECOVERY_ACTIVE);
383         if (ret != 0) {
384                 printf("Unable to set recovery mode\n");
385                 return ret;
386         }
387
388         return 0;
389 }
390
391
392 /*
393   display monitoring mode of a remote node
394  */
395 static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
396 {
397         uint32_t monmode;
398         int ret;
399
400         ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.vnn, &monmode);
401         if (ret != 0) {
402                 printf("Unable to get monmode from node %u\n", options.vnn);
403                 return ret;
404         }
405         printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
406
407         return 0;
408 }
409
410 /*
411   set the monitoring mode of a remote node
412  */
413 static int control_setmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
414 {
415         uint32_t monmode;
416         int ret;
417
418         if (argc < 1) {
419                 usage();
420         }
421
422         monmode = strtoul(argv[0], NULL, 0);
423
424         ret = ctdb_ctrl_setmonmode(ctdb, TIMELIMIT(), options.vnn, monmode);
425         if (ret != 0) {
426                 printf("Unable to set monmode on node %u\n", options.vnn);
427                 return ret;
428         }
429
430         return 0;
431 }
432
433 /*
434   display remote list of keys/data for a db
435  */
436 static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
437 {
438         const char *db_name;
439         struct ctdb_db_context *ctdb_db;
440         int ret;
441
442         if (argc < 1) {
443                 usage();
444         }
445
446         db_name = argv[0];
447         ctdb_db = ctdb_attach(ctdb, db_name);
448
449         if (ctdb_db == NULL) {
450                 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
451                 return -1;
452         }
453
454         /* traverse and dump the cluster tdb */
455         ret = ctdb_dump_db(ctdb_db, stdout);
456         if (ret == -1) {
457                 printf("Unable to dump database\n");
458                 return -1;
459         }
460         talloc_free(ctdb_db);
461
462         printf("Dumped %d records\n", ret);
463         return 0;
464 }
465
466
467 /*
468   display a list of the databases on a remote ctdb
469  */
470 static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
471 {
472         int i, ret;
473         struct ctdb_dbid_map *dbmap=NULL;
474
475         ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &dbmap);
476         if (ret != 0) {
477                 printf("Unable to get dbids from node %u\n", options.vnn);
478                 return ret;
479         }
480
481         printf("Number of databases:%d\n", dbmap->num);
482         for(i=0;i<dbmap->num;i++){
483                 const char *path;
484                 const char *name;
485
486                 ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &path);
487                 ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &name);
488                 printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path);
489         }
490
491         return 0;
492 }
493
494 /*
495   ping a node
496  */
497 static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
498 {
499         int ret, i;
500         uint32_t *nodes;
501         uint32_t num_nodes;
502
503         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
504         CTDB_NO_MEMORY(ctdb, nodes);
505
506         for (i=0;i<num_nodes;i++) {
507                 struct timeval tv = timeval_current();
508                 ret = ctdb_ctrl_ping(ctdb, nodes[i]);
509                 if (ret == -1) {
510                         printf("Unable to get ping response from node %u\n", nodes[i]);
511                 } else {
512                         printf("response from %u time=%.6f sec  (%d clients)\n", 
513                                nodes[i], timeval_elapsed(&tv), ret);
514                 }
515         }
516         talloc_free(nodes);
517         return 0;
518 }
519
520
521 /*
522   display debug level on a node
523  */
524 static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
525 {
526         int ret, i;
527         uint32_t *nodes;
528         uint32_t num_nodes;
529         uint32_t level;
530
531         if (options.vnn != CTDB_BROADCAST_ALL) {
532                 ret = ctdb_ctrl_get_debuglevel(ctdb, options.vnn, &level);
533                 if (ret != 0) {
534                         printf("Unable to get debuglevel response from node %u\n", 
535                                 options.vnn);
536                 } else {
537                         printf("Node %u is at debug level %u\n", options.vnn, level);
538                 }
539                 return 0;
540         }
541
542         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
543         CTDB_NO_MEMORY(ctdb, nodes);
544         
545         for (i=0;i<num_nodes;i++) {
546                 ret = ctdb_ctrl_get_debuglevel(ctdb, nodes[i], &level);
547                 if (ret != 0) {
548                         printf("Unable to get debuglevel response from node %u\n", 
549                                 nodes[i]);
550                 } else {
551                         printf("Node %u is at debug level %u\n", nodes[i], level);
552                 }
553         }
554         talloc_free(nodes);
555         return 0;
556 }
557
558
559 /*
560   set debug level on a node or all nodes
561  */
562 static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
563 {
564         int ret;
565         uint32_t level, i;
566         uint32_t *nodes;
567         uint32_t num_nodes;
568
569         if (argc < 1) {
570                 usage();
571         }
572
573         level = strtoul(argv[0], NULL, 0);
574
575         if (options.vnn != CTDB_BROADCAST_ALL) {
576                 ret = ctdb_ctrl_set_debuglevel(ctdb, options.vnn, level);
577                 if (ret != 0) {
578                         printf("Unable to set debug level on node %u\n", options.vnn);
579                 }
580                 return 0;
581         }
582
583         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
584         CTDB_NO_MEMORY(ctdb, nodes);
585         for (i=0;i<num_nodes;i++) {
586                 ret = ctdb_ctrl_set_debuglevel(ctdb, nodes[i], level);
587                 if (ret != 0) {
588                         printf("Unable to set debug level on node %u\n", nodes[i]);
589                         break;
590                 }
591         }
592         talloc_free(nodes);
593         return 0;
594 }
595
596
597 /*
598   freeze a node
599  */
600 static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
601 {
602         int ret=0, count=0;
603         uint32_t i;
604         uint32_t *nodes;
605         uint32_t num_nodes;
606
607         if (options.vnn != CTDB_BROADCAST_ALL) {
608                 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
609                 if (ret != 0) {
610                         printf("Unable to freeze node %u\n", options.vnn);
611                 }               
612                 return 0;
613         }
614
615         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
616         CTDB_NO_MEMORY(ctdb, nodes);
617         for (i=0;i<num_nodes;i++) {
618                 int res = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), nodes[i]);
619                 if (res != 0) {
620                         printf("Warning: Unable to freeze node %u\n", nodes[i]);
621                 } else {
622                         count++;
623                 }
624                 ret |= res;
625         }
626         printf("Froze %u nodes\n", count);
627         talloc_free(nodes);
628         return 0;
629 }
630
631 /*
632   thaw a node
633  */
634 static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
635 {
636         int ret=0, count=0;
637         uint32_t i;
638         uint32_t *nodes;
639         uint32_t num_nodes;
640
641         if (options.vnn != CTDB_BROADCAST_ALL) {
642                 ret = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), options.vnn);
643                 if (ret != 0) {
644                         printf("Unable to thaw node %u\n", options.vnn);
645                 }               
646                 return 0;
647         }
648
649         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
650         CTDB_NO_MEMORY(ctdb, nodes);
651         for (i=0;i<num_nodes;i++) {
652                 int res = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), nodes[i]);
653                 if (res != 0) {
654                         printf("Warning: Unable to thaw node %u\n", nodes[i]);
655                 } else {
656                         count++;
657                 }
658                 ret |= res;
659         }
660         printf("Thawed %u nodes\n", count);
661         talloc_free(nodes);
662         return 0;
663 }
664
665
666 /*
667   attach to a database
668  */
669 static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv)
670 {
671         const char *db_name;
672         struct ctdb_db_context *ctdb_db;
673
674         if (argc < 1) {
675                 usage();
676         }
677         db_name = argv[0];
678
679         ctdb_db = ctdb_attach(ctdb, db_name);
680         if (ctdb_db == NULL) {
681                 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
682                 return -1;
683         }
684
685         return 0;
686 }
687
688 /*
689   dump memory usage
690  */
691 static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
692 {
693         return ctdb_control(ctdb, options.vnn, 0, CTDB_CONTROL_DUMP_MEMORY,
694                             CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL, NULL);
695 }
696
697
698 static const struct {
699         const char *name;
700         int (*fn)(struct ctdb_context *, int, const char **);
701         const char *msg;
702         const char *args;
703 } ctdb_commands[] = {
704         { "status",          control_status,            "show node status" },
705         { "ping",            control_ping,              "ping all nodes" },
706         { "statistics",      control_statistics,        "show statistics" },
707         { "statisticsreset", control_statistics_reset,  "reset statistics"},
708         { "process-exists",  control_process_exists,    "check if a process exists on a node",  "<pid>"},
709         { "getdbmap",        control_getdbmap,          "show the database map" },
710         { "catdb",           control_catdb,             "dump a database" ,                     "<dbname>"},
711         { "getmonmode",      control_getmonmode,        "show monitoring mode" },
712         { "setmonmode",      control_setmonmode,        "set monitoring mode" },
713         { "setdebug",        control_setdebug,          "set debug level",                      "<debuglevel>" },
714         { "getdebug",        control_getdebug,          "get debug level" },
715         { "attach",          control_attach,            "attach to a database",                 "<dbname>" },
716         { "dumpmemory",      control_dumpmemory,        "dump memory map to logs" },
717         { "getpid",          control_getpid,            "get ctdbd process ID" },
718         { "shutdown",        control_shutdown,          "shutdown ctdbd" },
719         { "recover",         control_recover,           "force recovery" },
720         { "freeze",          control_freeze,            "freeze all databases" },
721         { "thaw",            control_thaw,              "thaw all databases" },
722 };
723
724 /*
725   show usage message
726  */
727 static void usage(void)
728 {
729         int i;
730         printf(
731 "Usage: ctdb [options] <control>\n" \
732 "Options:\n" \
733 "   -n <node>          choose node number, or 'all' (defaults to local node)\n"
734 "   -Y                 generate machinereadable output\n"
735 "   -t <timelimit>     set timelimit for control in seconds (default %u)\n", options.timelimit);
736         printf("Controls:\n");
737         for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
738                 printf("  %-15s %-20s  %s\n", 
739                        ctdb_commands[i].name, 
740                        ctdb_commands[i].args?ctdb_commands[i].args:"",
741                        ctdb_commands[i].msg);
742         }
743         exit(1);
744 }
745
746
747 /*
748   main program
749 */
750 int main(int argc, const char *argv[])
751 {
752         struct ctdb_context *ctdb;
753         char *nodestring = NULL;
754         struct poptOption popt_options[] = {
755                 POPT_AUTOHELP
756                 POPT_CTDB_CMDLINE
757                 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
758                 { "node",      'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
759                 { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
760                 POPT_TABLEEND
761         };
762         int opt;
763         const char **extra_argv;
764         int extra_argc = 0;
765         int ret=-1, i;
766         poptContext pc;
767         struct event_context *ev;
768         const char *control;
769
770         /* set some defaults */
771         options.timelimit = 3;
772         options.vnn = CTDB_CURRENT_NODE;
773
774         pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
775
776         while ((opt = poptGetNextOpt(pc)) != -1) {
777                 switch (opt) {
778                 default:
779                         fprintf(stderr, "Invalid option %s: %s\n", 
780                                 poptBadOption(pc, 0), poptStrerror(opt));
781                         exit(1);
782                 }
783         }
784
785         /* setup the remaining options for the main program to use */
786         extra_argv = poptGetArgs(pc);
787         if (extra_argv) {
788                 extra_argv++;
789                 while (extra_argv[extra_argc]) extra_argc++;
790         }
791
792         if (extra_argc < 1) {
793                 usage();
794         }
795
796         /* setup the node number to contact */
797         if (nodestring != NULL) {
798                 if (strcmp(nodestring, "all") == 0) {
799                         options.vnn = CTDB_BROADCAST_ALL;
800                 } else {
801                         options.vnn = strtoul(nodestring, NULL, 0);
802                 }
803         }
804
805         control = extra_argv[0];
806
807         ev = event_context_init(NULL);
808
809         /* initialise ctdb */
810         ctdb = ctdb_cmdline_client(ev);
811         if (ctdb == NULL) {
812                 printf("Failed to init ctdb\n");
813                 exit(1);
814         }
815
816         for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
817                 if (strcmp(control, ctdb_commands[i].name) == 0) {
818                         ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
819                         break;
820                 }
821         }
822
823         if (i == ARRAY_SIZE(ctdb_commands)) {
824                 printf("Unknown control '%s'\n", control);
825                 exit(1);
826         }
827
828         return ret;
829 }