merge from tridge
[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.register_srvid),
111                 STATISTICS_FIELD(controls.deregister_srvid),
112                 STATISTICS_FIELD(timeouts.call),
113                 STATISTICS_FIELD(timeouts.control),
114                 STATISTICS_FIELD(timeouts.traverse),
115                 STATISTICS_FIELD(total_calls),
116                 STATISTICS_FIELD(pending_calls),
117                 STATISTICS_FIELD(lockwait_calls),
118                 STATISTICS_FIELD(pending_lockwait_calls),
119                 STATISTICS_FIELD(memory_used),
120                 STATISTICS_FIELD(max_hop_count),
121         };
122         printf("CTDB version %u\n", CTDB_VERSION);
123         for (i=0;i<ARRAY_SIZE(fields);i++) {
124                 if (strchr(fields[i].name, '.')) {
125                         preflen = strcspn(fields[i].name, ".")+1;
126                         if (!prefix || strncmp(prefix, fields[i].name, preflen) != 0) {
127                                 prefix = fields[i].name;
128                                 printf(" %*.*s\n", preflen-1, preflen-1, fields[i].name);
129                         }
130                 } else {
131                         preflen = 0;
132                 }
133                 printf(" %*s%-22s%*s%10u\n", 
134                        preflen?4:0, "",
135                        fields[i].name+preflen, 
136                        preflen?0:4, "",
137                        *(uint32_t *)(fields[i].offset+(uint8_t *)s));
138         }
139         printf(" %-30s     %.6f sec\n", "max_call_latency", s->max_call_latency);
140         printf(" %-30s     %.6f sec\n", "max_lockwait_latency", s->max_lockwait_latency);
141         talloc_free(tmp_ctx);
142 }
143
144 /*
145   display remote ctdb statistics combined from all nodes
146  */
147 static int control_statistics_all(struct ctdb_context *ctdb)
148 {
149         int ret, i;
150         struct ctdb_statistics statistics;
151         uint32_t *nodes;
152         uint32_t num_nodes;
153
154         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
155         CTDB_NO_MEMORY(ctdb, nodes);
156         
157         ZERO_STRUCT(statistics);
158
159         for (i=0;i<num_nodes;i++) {
160                 struct ctdb_statistics s1;
161                 int j;
162                 uint32_t *v1 = (uint32_t *)&s1;
163                 uint32_t *v2 = (uint32_t *)&statistics;
164                 uint32_t num_ints = 
165                         offsetof(struct ctdb_statistics, __last_counter) / sizeof(uint32_t);
166                 ret = ctdb_ctrl_statistics(ctdb, nodes[i], &s1);
167                 if (ret != 0) {
168                         printf("Unable to get statistics from node %u\n", nodes[i]);
169                         return ret;
170                 }
171                 for (j=0;j<num_ints;j++) {
172                         v2[j] += v1[j];
173                 }
174                 statistics.max_hop_count = 
175                         MAX(statistics.max_hop_count, s1.max_hop_count);
176                 statistics.max_call_latency = 
177                         MAX(statistics.max_call_latency, s1.max_call_latency);
178                 statistics.max_lockwait_latency = 
179                         MAX(statistics.max_lockwait_latency, s1.max_lockwait_latency);
180         }
181         talloc_free(nodes);
182         printf("Gathered statistics for %u nodes\n", num_nodes);
183         show_statistics(&statistics);
184         return 0;
185 }
186
187 /*
188   display remote ctdb statistics
189  */
190 static int control_statistics(struct ctdb_context *ctdb, int argc, const char **argv)
191 {
192         int ret;
193         struct ctdb_statistics statistics;
194
195         if (options.vnn == CTDB_BROADCAST_ALL) {
196                 return control_statistics_all(ctdb);
197         }
198
199         ret = ctdb_ctrl_statistics(ctdb, options.vnn, &statistics);
200         if (ret != 0) {
201                 printf("Unable to get statistics from node %u\n", options.vnn);
202                 return ret;
203         }
204         show_statistics(&statistics);
205         return 0;
206 }
207
208
209 /*
210   reset statistics on all nodes
211  */
212 static int control_statistics_reset_all(struct ctdb_context *ctdb)
213 {
214         int ret, i;
215         uint32_t *nodes;
216         uint32_t num_nodes;
217
218         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
219         CTDB_NO_MEMORY(ctdb, nodes);
220         
221         for (i=0;i<num_nodes;i++) {
222                 ret = ctdb_statistics_reset(ctdb, nodes[i]);
223                 if (ret != 0) {
224                         printf("Unable to reset statistics on node %u\n", nodes[i]);
225                         return ret;
226                 }
227         }
228         talloc_free(nodes);
229         return 0;
230 }
231
232
233 /*
234   reset remote ctdb statistics
235  */
236 static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const char **argv)
237 {
238         int ret;
239
240         if (options.vnn == CTDB_BROADCAST_ALL) {
241                 return control_statistics_reset_all(ctdb);
242         }
243
244         ret = ctdb_statistics_reset(ctdb, options.vnn);
245         if (ret != 0) {
246                 printf("Unable to reset statistics on node %u\n", options.vnn);
247                 return ret;
248         }
249         return 0;
250 }
251
252
253 /*
254   display remote ctdb status
255  */
256 static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
257 {
258         int i, ret;
259         struct ctdb_vnn_map *vnnmap=NULL;
260         struct ctdb_node_map *nodemap=NULL;
261         uint32_t recmode, recmaster;
262         uint32_t myvnn;
263
264         if (options.vnn == CTDB_BROADCAST_ALL) {
265                 uint32_t *nodes;
266                 uint32_t num_nodes;
267                 ret = 0;
268
269                 nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
270                 CTDB_NO_MEMORY(ctdb, nodes);
271         
272                 for (i=0;i<num_nodes;i++) {
273                         options.vnn = nodes[i];
274                         ret |= control_status(ctdb, argc, argv);
275                 }
276                 return ret;
277         }
278
279         myvnn = ctdb_ctrl_getvnn(ctdb, TIMELIMIT(), options.vnn);
280
281         ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.vnn, ctdb, &nodemap);
282         if (ret != 0) {
283                 printf("Unable to get nodemap from node %u\n", options.vnn);
284                 return ret;
285         }
286
287         if(options.machinereadable){
288                 printf(":Node:IP:Status:\n");
289                 for(i=0;i<nodemap->num;i++){
290                         printf(":%d:%s:%d:\n", nodemap->nodes[i].vnn,
291                                 inet_ntoa(nodemap->nodes[i].sin.sin_addr),
292                                 !!nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED);
293                 }
294                 return 0;
295         }
296
297         printf("Number of nodes:%d\n", nodemap->num);
298         for(i=0;i<nodemap->num;i++){
299                 printf("vnn:%d %-16s %s%s\n", nodemap->nodes[i].vnn,
300                         inet_ntoa(nodemap->nodes[i].sin.sin_addr),
301                         nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED?
302                                 "CONNECTED":"UNAVAILABLE",
303                         nodemap->nodes[i].vnn == myvnn?" (THIS NODE)":"");
304         }
305
306         ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &vnnmap);
307         if (ret != 0) {
308                 printf("Unable to get vnnmap from node %u\n", options.vnn);
309                 return ret;
310         }
311         printf("Generation:%d\n",vnnmap->generation);
312         printf("Size:%d\n",vnnmap->size);
313         for(i=0;i<vnnmap->size;i++){
314                 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
315         }
316
317         ret = ctdb_ctrl_getrecmode(ctdb, TIMELIMIT(), options.vnn, &recmode);
318         if (ret != 0) {
319                 printf("Unable to get recmode from node %u\n", options.vnn);
320                 return ret;
321         }
322         printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
323
324         ret = ctdb_ctrl_getrecmaster(ctdb, TIMELIMIT(), options.vnn, &recmaster);
325         if (ret != 0) {
326                 printf("Unable to get recmaster from node %u\n", options.vnn);
327                 return ret;
328         }
329         printf("Recovery master:%d\n",recmaster);
330
331         return 0;
332 }
333
334 /*
335   display pid of a ctdb daemon
336  */
337 static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
338 {
339         uint32_t pid;
340         int ret;
341
342         ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.vnn, &pid);
343         if (ret != 0) {
344                 printf("Unable to get daemon pid from node %u\n", options.vnn);
345                 return ret;
346         }
347         printf("Pid:%d\n", pid);
348
349         return 0;
350 }
351
352 /*
353   shutdown a daemon
354  */
355 static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv)
356 {
357         int ret;
358
359         ret = ctdb_ctrl_shutdown(ctdb, timeval_current_ofs(1, 0), options.vnn);
360         if (ret != 0) {
361                 printf("Unable to shutdown node %u\n", options.vnn);
362                 return ret;
363         }
364
365         return 0;
366 }
367
368 /*
369   trigger a recovery
370  */
371 static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv)
372 {
373         int ret;
374
375         ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
376         if (ret != 0) {
377                 printf("Unable to freeze node\n");
378                 return ret;
379         }
380
381         ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.vnn, CTDB_RECOVERY_ACTIVE);
382         if (ret != 0) {
383                 printf("Unable to set recovery mode\n");
384                 return ret;
385         }
386
387         return 0;
388 }
389
390
391 /*
392   display monitoring mode of a remote node
393  */
394 static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
395 {
396         uint32_t monmode;
397         int ret;
398
399         ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.vnn, &monmode);
400         if (ret != 0) {
401                 printf("Unable to get monmode from node %u\n", options.vnn);
402                 return ret;
403         }
404         printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
405
406         return 0;
407 }
408
409 /*
410   set the monitoring mode of a remote node
411  */
412 static int control_setmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
413 {
414         uint32_t monmode;
415         int ret;
416
417         if (argc < 1) {
418                 usage();
419         }
420
421         monmode = strtoul(argv[0], NULL, 0);
422
423         ret = ctdb_ctrl_setmonmode(ctdb, TIMELIMIT(), options.vnn, monmode);
424         if (ret != 0) {
425                 printf("Unable to set monmode on node %u\n", options.vnn);
426                 return ret;
427         }
428
429         return 0;
430 }
431
432 /*
433   display remote list of keys/data for a db
434  */
435 static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
436 {
437         const char *db_name;
438         struct ctdb_db_context *ctdb_db;
439         int ret;
440
441         if (argc < 1) {
442                 usage();
443         }
444
445         db_name = argv[0];
446         ctdb_db = ctdb_attach(ctdb, db_name);
447
448         if (ctdb_db == NULL) {
449                 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
450                 return -1;
451         }
452
453         /* traverse and dump the cluster tdb */
454         ret = ctdb_dump_db(ctdb_db, stdout);
455         if (ret == -1) {
456                 printf("Unable to dump database\n");
457                 return -1;
458         }
459         talloc_free(ctdb_db);
460
461         printf("Dumped %d records\n", ret);
462         return 0;
463 }
464
465
466 /*
467   display a list of the databases on a remote ctdb
468  */
469 static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
470 {
471         int i, ret;
472         struct ctdb_dbid_map *dbmap=NULL;
473
474         ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.vnn, ctdb, &dbmap);
475         if (ret != 0) {
476                 printf("Unable to get dbids from node %u\n", options.vnn);
477                 return ret;
478         }
479
480         printf("Number of databases:%d\n", dbmap->num);
481         for(i=0;i<dbmap->num;i++){
482                 const char *path;
483                 const char *name;
484
485                 ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &path);
486                 ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.vnn, dbmap->dbids[i], ctdb, &name);
487                 printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path);
488         }
489
490         return 0;
491 }
492
493 /*
494   ping a node
495  */
496 static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
497 {
498         int ret, i;
499         uint32_t *nodes;
500         uint32_t num_nodes;
501
502         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
503         CTDB_NO_MEMORY(ctdb, nodes);
504
505         for (i=0;i<num_nodes;i++) {
506                 struct timeval tv = timeval_current();
507                 ret = ctdb_ctrl_ping(ctdb, nodes[i]);
508                 if (ret == -1) {
509                         printf("Unable to get ping response from node %u\n", nodes[i]);
510                 } else {
511                         printf("response from %u time=%.6f sec  (%d clients)\n", 
512                                nodes[i], timeval_elapsed(&tv), ret);
513                 }
514         }
515         talloc_free(nodes);
516         return 0;
517 }
518
519
520 /*
521   get a tunable
522  */
523 static int control_getvar(struct ctdb_context *ctdb, int argc, const char **argv)
524 {
525         const char *name;
526         uint32_t value;
527         int ret;
528
529         if (argc < 1) {
530                 usage();
531         }
532
533         name = argv[0];
534         ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.vnn, name, &value);
535         if (ret == -1) {
536                 printf("Unable to get tunable variable '%s'\n", name);
537                 return -1;
538         }
539
540         printf("%-17s = %u\n", name, value);
541         return 0;
542 }
543
544 /*
545   set a tunable
546  */
547 static int control_setvar(struct ctdb_context *ctdb, int argc, const char **argv)
548 {
549         const char *name;
550         uint32_t value;
551         int ret;
552
553         if (argc < 2) {
554                 usage();
555         }
556
557         name = argv[0];
558         value = strtoul(argv[1], NULL, 0);
559
560         ret = ctdb_ctrl_set_tunable(ctdb, TIMELIMIT(), options.vnn, name, value);
561         if (ret == -1) {
562                 printf("Unable to set tunable variable '%s'\n", name);
563                 return -1;
564         }
565         return 0;
566 }
567
568 /*
569   list all tunables
570  */
571 static int control_listvars(struct ctdb_context *ctdb, int argc, const char **argv)
572 {
573         uint32_t count;
574         const char **list;
575         int ret, i;
576
577         ret = ctdb_ctrl_list_tunables(ctdb, TIMELIMIT(), options.vnn, ctdb, &list, &count);
578         if (ret == -1) {
579                 printf("Unable to list tunable variables\n");
580                 return -1;
581         }
582
583         for (i=0;i<count;i++) {
584                 control_getvar(ctdb, 1, &list[i]);
585         }
586
587         talloc_free(list);
588         
589         return 0;
590 }
591
592 /*
593   display debug level on a node
594  */
595 static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
596 {
597         int ret, i;
598         uint32_t *nodes;
599         uint32_t num_nodes;
600         uint32_t level;
601
602         if (options.vnn != CTDB_BROADCAST_ALL) {
603                 ret = ctdb_ctrl_get_debuglevel(ctdb, options.vnn, &level);
604                 if (ret != 0) {
605                         printf("Unable to get debuglevel response from node %u\n", 
606                                 options.vnn);
607                 } else {
608                         printf("Node %u is at debug level %u\n", options.vnn, level);
609                 }
610                 return 0;
611         }
612
613         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
614         CTDB_NO_MEMORY(ctdb, nodes);
615         
616         for (i=0;i<num_nodes;i++) {
617                 ret = ctdb_ctrl_get_debuglevel(ctdb, nodes[i], &level);
618                 if (ret != 0) {
619                         printf("Unable to get debuglevel response from node %u\n", 
620                                 nodes[i]);
621                 } else {
622                         printf("Node %u is at debug level %u\n", nodes[i], level);
623                 }
624         }
625         talloc_free(nodes);
626         return 0;
627 }
628
629
630 /*
631   set debug level on a node or all nodes
632  */
633 static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
634 {
635         int ret;
636         uint32_t level, i;
637         uint32_t *nodes;
638         uint32_t num_nodes;
639
640         if (argc < 1) {
641                 usage();
642         }
643
644         level = strtoul(argv[0], NULL, 0);
645
646         if (options.vnn != CTDB_BROADCAST_ALL) {
647                 ret = ctdb_ctrl_set_debuglevel(ctdb, options.vnn, level);
648                 if (ret != 0) {
649                         printf("Unable to set debug level on node %u\n", options.vnn);
650                 }
651                 return 0;
652         }
653
654         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
655         CTDB_NO_MEMORY(ctdb, nodes);
656         for (i=0;i<num_nodes;i++) {
657                 ret = ctdb_ctrl_set_debuglevel(ctdb, nodes[i], level);
658                 if (ret != 0) {
659                         printf("Unable to set debug level on node %u\n", nodes[i]);
660                         break;
661                 }
662         }
663         talloc_free(nodes);
664         return 0;
665 }
666
667
668 /*
669   freeze a node
670  */
671 static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
672 {
673         int ret=0, count=0;
674         uint32_t i;
675         uint32_t *nodes;
676         uint32_t num_nodes;
677
678         if (options.vnn != CTDB_BROADCAST_ALL) {
679                 ret = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), options.vnn);
680                 if (ret != 0) {
681                         printf("Unable to freeze node %u\n", options.vnn);
682                 }               
683                 return 0;
684         }
685
686         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
687         CTDB_NO_MEMORY(ctdb, nodes);
688         for (i=0;i<num_nodes;i++) {
689                 int res = ctdb_ctrl_freeze(ctdb, TIMELIMIT(), nodes[i]);
690                 if (res != 0) {
691                         printf("Warning: Unable to freeze node %u\n", nodes[i]);
692                 } else {
693                         count++;
694                 }
695                 ret |= res;
696         }
697         printf("Froze %u nodes\n", count);
698         talloc_free(nodes);
699         return 0;
700 }
701
702 /*
703   thaw a node
704  */
705 static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
706 {
707         int ret=0, count=0;
708         uint32_t i;
709         uint32_t *nodes;
710         uint32_t num_nodes;
711
712         if (options.vnn != CTDB_BROADCAST_ALL) {
713                 ret = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), options.vnn);
714                 if (ret != 0) {
715                         printf("Unable to thaw node %u\n", options.vnn);
716                 }               
717                 return 0;
718         }
719
720         nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
721         CTDB_NO_MEMORY(ctdb, nodes);
722         for (i=0;i<num_nodes;i++) {
723                 int res = ctdb_ctrl_thaw(ctdb, TIMELIMIT(), nodes[i]);
724                 if (res != 0) {
725                         printf("Warning: Unable to thaw node %u\n", nodes[i]);
726                 } else {
727                         count++;
728                 }
729                 ret |= res;
730         }
731         printf("Thawed %u nodes\n", count);
732         talloc_free(nodes);
733         return 0;
734 }
735
736
737 /*
738   attach to a database
739  */
740 static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv)
741 {
742         const char *db_name;
743         struct ctdb_db_context *ctdb_db;
744
745         if (argc < 1) {
746                 usage();
747         }
748         db_name = argv[0];
749
750         ctdb_db = ctdb_attach(ctdb, db_name);
751         if (ctdb_db == NULL) {
752                 DEBUG(0,("Unable to attach to database '%s'\n", db_name));
753                 return -1;
754         }
755
756         return 0;
757 }
758
759 /*
760   dump memory usage
761  */
762 static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
763 {
764         return ctdb_control(ctdb, options.vnn, 0, CTDB_CONTROL_DUMP_MEMORY,
765                             CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL, NULL);
766 }
767
768
769 static const struct {
770         const char *name;
771         int (*fn)(struct ctdb_context *, int, const char **);
772         const char *msg;
773         const char *args;
774 } ctdb_commands[] = {
775         { "status",          control_status,            "show node status" },
776         { "ping",            control_ping,              "ping all nodes" },
777         { "getvar",          control_getvar,            "get a tunable variable",               "<name>"},
778         { "setvar",          control_setvar,            "set a tunable variable",               "<name> <value>"},
779         { "listvars",        control_listvars,          "list tunable variables"},
780         { "statistics",      control_statistics,        "show statistics" },
781         { "statisticsreset", control_statistics_reset,  "reset statistics"},
782         { "process-exists",  control_process_exists,    "check if a process exists on a node",  "<pid>"},
783         { "getdbmap",        control_getdbmap,          "show the database map" },
784         { "catdb",           control_catdb,             "dump a database" ,                     "<dbname>"},
785         { "getmonmode",      control_getmonmode,        "show monitoring mode" },
786         { "setmonmode",      control_setmonmode,        "set monitoring mode" },
787         { "setdebug",        control_setdebug,          "set debug level",                      "<debuglevel>" },
788         { "getdebug",        control_getdebug,          "get debug level" },
789         { "attach",          control_attach,            "attach to a database",                 "<dbname>" },
790         { "dumpmemory",      control_dumpmemory,        "dump memory map to logs" },
791         { "getpid",          control_getpid,            "get ctdbd process ID" },
792         { "shutdown",        control_shutdown,          "shutdown ctdbd" },
793         { "recover",         control_recover,           "force recovery" },
794         { "freeze",          control_freeze,            "freeze all databases" },
795         { "thaw",            control_thaw,              "thaw all databases" },
796 };
797
798 /*
799   show usage message
800  */
801 static void usage(void)
802 {
803         int i;
804         printf(
805 "Usage: ctdb [options] <control>\n" \
806 "Options:\n" \
807 "   -n <node>          choose node number, or 'all' (defaults to local node)\n"
808 "   -Y                 generate machinereadable output\n"
809 "   -t <timelimit>     set timelimit for control in seconds (default %u)\n", options.timelimit);
810         printf("Controls:\n");
811         for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
812                 printf("  %-15s %-20s  %s\n", 
813                        ctdb_commands[i].name, 
814                        ctdb_commands[i].args?ctdb_commands[i].args:"",
815                        ctdb_commands[i].msg);
816         }
817         exit(1);
818 }
819
820
821 /*
822   main program
823 */
824 int main(int argc, const char *argv[])
825 {
826         struct ctdb_context *ctdb;
827         char *nodestring = NULL;
828         struct poptOption popt_options[] = {
829                 POPT_AUTOHELP
830                 POPT_CTDB_CMDLINE
831                 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
832                 { "node",      'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
833                 { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
834                 POPT_TABLEEND
835         };
836         int opt;
837         const char **extra_argv;
838         int extra_argc = 0;
839         int ret=-1, i;
840         poptContext pc;
841         struct event_context *ev;
842         const char *control;
843
844         /* set some defaults */
845         options.timelimit = 3;
846         options.vnn = CTDB_CURRENT_NODE;
847
848         pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
849
850         while ((opt = poptGetNextOpt(pc)) != -1) {
851                 switch (opt) {
852                 default:
853                         fprintf(stderr, "Invalid option %s: %s\n", 
854                                 poptBadOption(pc, 0), poptStrerror(opt));
855                         exit(1);
856                 }
857         }
858
859         /* setup the remaining options for the main program to use */
860         extra_argv = poptGetArgs(pc);
861         if (extra_argv) {
862                 extra_argv++;
863                 while (extra_argv[extra_argc]) extra_argc++;
864         }
865
866         if (extra_argc < 1) {
867                 usage();
868         }
869
870         /* setup the node number to contact */
871         if (nodestring != NULL) {
872                 if (strcmp(nodestring, "all") == 0) {
873                         options.vnn = CTDB_BROADCAST_ALL;
874                 } else {
875                         options.vnn = strtoul(nodestring, NULL, 0);
876                 }
877         }
878
879         control = extra_argv[0];
880
881         ev = event_context_init(NULL);
882
883         /* initialise ctdb */
884         ctdb = ctdb_cmdline_client(ev);
885         if (ctdb == NULL) {
886                 printf("Failed to init ctdb\n");
887                 exit(1);
888         }
889
890         for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
891                 if (strcmp(control, ctdb_commands[i].name) == 0) {
892                         ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
893                         break;
894                 }
895         }
896
897         if (i == ARRAY_SIZE(ctdb_commands)) {
898                 printf("Unknown control '%s'\n", control);
899                 exit(1);
900         }
901
902         return ret;
903 }