r13316: Let the carnage begin....
[idra/samba.git] / source3 / utils / smbcontrol.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Send messages to other Samba daemons
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 1994-1998
8    Copyright (C) Martin Pool 2001-2002
9    Copyright (C) Simo Sorce 2002
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 /* Default timeout value when waiting for replies (in seconds) */
29
30 #define DEFAULT_TIMEOUT 10
31
32 static int timeout = DEFAULT_TIMEOUT;
33 static int num_replies;         /* Used by message callback fns */
34
35 /* Send a message to a destination pid.  Zero means broadcast smbd. */
36
37 static BOOL send_message(struct process_id pid, int msg_type,
38                          const void *buf, int len,
39                          BOOL duplicates)
40 {
41         TDB_CONTEXT *tdb;
42         BOOL ret;
43         int n_sent = 0;
44
45         if (!message_init())
46                 return False;
47
48         if (procid_to_pid(&pid) != 0)
49                 return message_send_pid(pid, msg_type, buf, len, duplicates);
50
51         tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
52                            TDB_DEFAULT, O_RDWR, 0);
53         if (!tdb) {
54                 fprintf(stderr,"Failed to open connections database"
55                         ": %s\n", strerror(errno));
56                 return False;
57         }
58         
59         ret = message_send_all(tdb,msg_type, buf, len, duplicates,
60                                &n_sent);
61         DEBUG(10,("smbcontrol/send_message: broadcast message to "
62                   "%d processes\n", n_sent));
63         
64         tdb_close(tdb);
65         
66         return ret;
67 }
68
69 /* Wait for one or more reply messages */
70
71 static void wait_replies(BOOL multiple_replies)
72 {
73         time_t start_time = time(NULL);
74
75         /* Wait around a bit.  This is pretty disgusting - we have to
76            busy-wait here as there is no nicer way to do it. */
77
78         do {
79                 message_dispatch();
80                 if (num_replies > 0 && !multiple_replies)
81                         break;
82                 sleep(1);
83         } while (timeout - (time(NULL) - start_time) > 0);
84 }
85
86 /* Message handler callback that displays the PID and a string on stdout */
87
88 static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len)
89 {
90         printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
91                (int)len, (const char *)buf);
92         num_replies++;
93 }
94
95 /* Message handler callback that displays a string on stdout */
96
97 static void print_string_cb(int msg_type, struct process_id pid,
98                             void *buf, size_t len)
99 {
100         printf("%.*s", (int)len, (const char *)buf);
101         num_replies++;
102 }
103
104 /* Send no message.  Useful for testing. */
105
106 static BOOL do_noop(const struct process_id pid,
107                     const int argc, const char **argv)
108 {
109         if (argc != 1) {
110                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
111                 return False;
112         }
113
114         /* Move along, nothing to see here */
115
116         return True;
117 }
118
119 /* Send a debug string */
120
121 static BOOL do_debug(const struct process_id pid,
122                      const int argc, const char **argv)
123 {
124         if (argc != 2) {
125                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
126                         "<debug-string>\n");
127                 return False;
128         }
129
130         return send_message(
131                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
132 }
133
134 /* Force a browser election */
135
136 static BOOL do_election(const struct process_id pid,
137                         const int argc, const char **argv)
138 {
139         if (argc != 1) {
140                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
141                 return False;
142         }
143
144         return send_message(
145                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
146 }
147
148 /* Ping a samba daemon process */
149
150 static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len)
151 {
152         char *src_string = procid_str(NULL, &pid);
153         printf("PONG from pid %s\n", src_string);
154         talloc_free(src_string);
155         num_replies++;
156 }
157
158 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
159 {
160         if (argc != 1) {
161                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
162                 return False;
163         }
164
165         /* Send a message and register our interest in a reply */
166
167         if (!send_message(pid, MSG_PING, NULL, 0, False))
168                 return False;
169
170         message_register(MSG_PONG, pong_cb);
171
172         wait_replies(procid_to_pid(&pid) == 0);
173
174         /* No replies were received within the timeout period */
175
176         if (num_replies == 0)
177                 printf("No replies received\n");
178
179         message_deregister(MSG_PONG);
180
181         return num_replies;
182 }
183
184 /* Set profiling options */
185
186 static BOOL do_profile(const struct process_id pid,
187                        const int argc, const char **argv)
188 {
189         int v;
190
191         if (argc != 2) {
192                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
193                         "<off|count|on|flush>\n");
194                 return False;
195         }
196
197         if (strcmp(argv[1], "off") == 0) {
198                 v = 0;
199         } else if (strcmp(argv[1], "count") == 0) {
200                 v = 1;
201         } else if (strcmp(argv[1], "on") == 0) {
202                 v = 2;
203         } else if (strcmp(argv[1], "flush") == 0) {
204                 v = 3;
205         } else {
206                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
207                 return False;
208         }
209
210         return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
211 }
212
213 /* Return the profiling level */
214
215 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len)
216 {
217         int level;
218         const char *s;
219
220         num_replies++;
221
222         if (len != sizeof(int)) {
223                 fprintf(stderr, "invalid message length %ld returned\n", 
224                         (unsigned long)len);
225                 return;
226         }
227
228         memcpy(&level, buf, sizeof(int));
229
230         switch (level) {
231         case 0:
232                 s = "not enabled";
233                 break;
234         case 1:
235                 s = "off";
236                 break;
237         case 3:
238                 s = "count only";
239                 break;
240         case 7:
241                 s = "count and time";
242                 break;
243         default:
244                 s = "BOGUS";
245                 break;
246         }
247         
248         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
249 }
250
251 static void profilelevel_rqst(int msg_type, struct process_id pid,
252                               void *buf, size_t len)
253 {
254         int v = 0;
255
256         /* Send back a dummy reply */
257
258         send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
259 }
260
261 static BOOL do_profilelevel(const struct process_id pid,
262                             const int argc, const char **argv)
263 {
264         if (argc != 1) {
265                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
266                 return False;
267         }
268
269         /* Send a message and register our interest in a reply */
270
271         if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
272                 return False;
273
274         message_register(MSG_PROFILELEVEL, profilelevel_cb);
275         message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
276
277         wait_replies(procid_to_pid(&pid) == 0);
278
279         /* No replies were received within the timeout period */
280
281         if (num_replies == 0)
282                 printf("No replies received\n");
283
284         message_deregister(MSG_PROFILE);
285
286         return num_replies;
287 }
288
289 /* Display debug level settings */
290
291 static BOOL do_debuglevel(const struct process_id pid,
292                           const int argc, const char **argv)
293 {
294         if (argc != 1) {
295                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
296                 return False;
297         }
298
299         /* Send a message and register our interest in a reply */
300
301         if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
302                 return False;
303
304         message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
305
306         wait_replies(procid_to_pid(&pid) == 0);
307
308         /* No replies were received within the timeout period */
309
310         if (num_replies == 0)
311                 printf("No replies received\n");
312
313         message_deregister(MSG_DEBUGLEVEL);
314
315         return num_replies;
316 }
317
318 /* Send a print notify message */
319
320 static BOOL do_printnotify(const struct process_id pid,
321                            const int argc, const char **argv)
322 {
323         const char *cmd;
324
325         /* Check for subcommand */
326
327         if (argc == 1) {
328                 fprintf(stderr, "Must specify subcommand:\n");
329                 fprintf(stderr, "\tqueuepause <printername>\n");
330                 fprintf(stderr, "\tqueueresume <printername>\n");
331                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
332                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
333                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
334                 fprintf(stderr, "\tprinter <printername> <comment|port|"
335                         "driver> <value>\n");
336                 
337                 return False;
338         }
339
340         cmd = argv[1];
341
342         if (strcmp(cmd, "queuepause") == 0) {
343
344                 if (argc != 3) {
345                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
346                                 " queuepause <printername>\n");
347                         return False;
348                 }
349                 
350                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
351
352                 goto send;
353
354         } else if (strcmp(cmd, "queueresume") == 0) {
355
356                 if (argc != 3) {
357                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
358                                 " queuereume <printername>\n");
359                         return False;
360                 }
361                 
362                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
363
364                 goto send;
365
366         } else if (strcmp(cmd, "jobpause") == 0) {
367                 int jobid;
368
369                 if (argc != 4) {
370                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
371                                 " jobpause <printername> <unix-jobid>\n");
372                         return False;
373                 }
374
375                 jobid = atoi(argv[3]);
376
377                 notify_job_status_byname(
378                         argv[2], jobid, JOB_STATUS_PAUSED, 
379                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
380
381                 goto send;
382
383         } else if (strcmp(cmd, "jobresume") == 0) {
384                 int jobid;
385
386                 if (argc != 4) {
387                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
388                                 " jobpause <printername> <unix-jobid>\n");
389                         return False;
390                 }
391
392                 jobid = atoi(argv[3]);
393
394                 notify_job_status_byname(
395                         argv[2], jobid, JOB_STATUS_QUEUED, 
396                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
397
398                 goto send;
399
400         } else if (strcmp(cmd, "jobdelete") == 0) {
401                 int jobid;
402
403                 if (argc != 4) {
404                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
405                                 " jobpause <printername> <unix-jobid>\n");
406                         return False;
407                 }
408
409                 jobid = atoi(argv[3]);
410
411                 notify_job_status_byname(
412                         argv[2], jobid, JOB_STATUS_DELETING,
413                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
414                 
415                 notify_job_status_byname(
416                         argv[2], jobid, JOB_STATUS_DELETING|
417                         JOB_STATUS_DELETED,
418                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
419
420                 goto send;
421
422         } else if (strcmp(cmd, "printer") == 0) {
423                 uint32 attribute;
424                 
425                 if (argc != 5) {
426                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
427                                 "printer <printername> <comment|port|driver> "
428                                 "<value>\n");
429                         return False;
430                 }
431
432                 if (strcmp(argv[3], "comment") == 0) {
433                         attribute = PRINTER_NOTIFY_COMMENT;
434                 } else if (strcmp(argv[3], "port") == 0) {
435                         attribute = PRINTER_NOTIFY_PORT_NAME;
436                 } else if (strcmp(argv[3], "driver") == 0) {
437                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
438                 } else {
439                         fprintf(stderr, "Invalid printer command '%s'\n",
440                                 argv[3]);
441                         return False;
442                 }
443
444                 notify_printer_byname(argv[2], attribute,
445                                       CONST_DISCARD(char *, argv[4]));
446
447                 goto send;
448         }
449
450         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
451         return False;
452
453 send:
454         print_notify_send_messages(0);
455         return True;
456 }
457
458 /* Close a share */
459
460 static BOOL do_closeshare(const struct process_id pid,
461                           const int argc, const char **argv)
462 {
463         if (argc != 2) {
464                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
465                         "<sharename>\n");
466                 return False;
467         }
468
469         return send_message(
470                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
471 }
472
473 /* Force a SAM synchronisation */
474
475 static BOOL do_samsync(const struct process_id pid,
476                        const int argc, const char **argv)
477 {
478         if (argc != 1) {
479                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
480                 return False;
481         }
482
483         return send_message(
484                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
485 }
486
487 /* Force a SAM replication */
488
489 static BOOL do_samrepl(const struct process_id pid,
490                        const int argc, const char **argv)
491 {
492         if (argc != 1) {
493                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
494                 return False;
495         }
496
497         return send_message(
498                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
499 }
500
501 /* Display talloc pool usage */
502
503 static BOOL do_poolusage(const struct process_id pid,
504                          const int argc, const char **argv)
505 {
506         if (argc != 1) {
507                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
508                 return False;
509         }
510
511         message_register(MSG_POOL_USAGE, print_string_cb);
512
513         /* Send a message and register our interest in a reply */
514
515         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
516                 return False;
517
518         wait_replies(procid_to_pid(&pid) == 0);
519
520         /* No replies were received within the timeout period */
521
522         if (num_replies == 0)
523                 printf("No replies received\n");
524
525         message_deregister(MSG_POOL_USAGE);
526
527         return num_replies;
528 }
529
530 /* Perform a dmalloc mark */
531
532 static BOOL do_dmalloc_mark(const struct process_id pid,
533                             const int argc, const char **argv)
534 {
535         if (argc != 1) {
536                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
537                 return False;
538         }
539
540         return send_message(
541                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
542 }
543
544 /* Perform a dmalloc changed */
545
546 static BOOL do_dmalloc_changed(const struct process_id pid,
547                                const int argc, const char **argv)
548 {
549         if (argc != 1) {
550                 fprintf(stderr, "Usage: smbcontrol <dest> "
551                         "dmalloc-log-changed\n");
552                 return False;
553         }
554
555         return send_message(
556                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
557 }
558
559 /* Shutdown a server process */
560
561 static BOOL do_shutdown(const struct process_id pid,
562                         const int argc, const char **argv)
563 {
564         if (argc != 1) {
565                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
566                 return False;
567         }
568
569         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
570 }
571
572 /* Notify a driver upgrade */
573
574 static BOOL do_drvupgrade(const struct process_id pid,
575                           const int argc, const char **argv)
576 {
577         if (argc != 2) {
578                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
579                         "<driver-name>\n");
580                 return False;
581         }
582
583         return send_message(
584                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
585 }
586
587 static BOOL do_winbind_online(const struct process_id pid,
588                              const int argc, const char **argv)
589 {
590         TDB_CONTEXT *tdb;
591
592         if (argc != 1) {
593                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
594                 return False;
595         }
596
597         if (!lp_winbind_offline_logon()) {
598                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
599                         "be set in the [global] section of smb.conf for this "
600                         "command to be allowed.\n");
601                 return False;
602         }
603
604         /* Remove the entry in the winbindd_cache tdb to tell a later
605            starting winbindd that we're online. */
606
607         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
608         if (!tdb) {
609                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
610                         lock_path("winbindd_cache.tdb"));
611                 return False;
612         }
613
614         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
615         tdb_close(tdb);
616
617         return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
618 }
619
620 static BOOL do_winbind_offline(const struct process_id pid,
621                              const int argc, const char **argv)
622 {
623         TDB_CONTEXT *tdb;
624         BOOL ret = False;
625         int retry = 0;
626
627         if (argc != 1) {
628                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
629                 return False;
630         }
631
632         if (!lp_winbind_offline_logon()) {
633                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
634                         "be set in the [global] section of smb.conf for this "
635                         "command to be allowed.\n");
636                 return False;
637         }
638
639         /* Create an entry in the winbindd_cache tdb to tell a later
640            starting winbindd that we're offline. We may actually create
641            it here... */
642
643         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
644                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
645                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
646
647         if (!tdb) {
648                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
649                         lock_path("winbindd_cache.tdb"));
650                 return False;
651         }
652
653         /* There's a potential race condition that if a child
654            winbindd detects a domain is online at the same time
655            we're trying to tell it to go offline that it might 
656            delete the record we add between us adding it and
657            sending the message. Minimize this by retrying up to
658            5 times. */
659
660         for (retry = 0; retry < 5; retry++) {
661                 int err;
662                 TDB_DATA d;
663                 ZERO_STRUCT(d);
664                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
665
666                 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
667
668                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
669                 tdb->ecode = 0;
670                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
671
672                 /* As this is a key with no data we don't need to free, we
673                    check for existence by looking at tdb_err. */
674
675                 err = tdb_error(tdb);
676
677                 if (err == TDB_ERR_NOEXIST) {
678                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
679                 } else {
680                         break;
681                 }
682         }
683
684         tdb_close(tdb);
685         return ret;
686 }
687
688 static BOOL do_reload_config(const struct process_id pid,
689                              const int argc, const char **argv)
690 {
691         if (argc != 1) {
692                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
693                 return False;
694         }
695
696         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
697 }
698
699 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
700 {
701         fstring unix_name;
702         memset( (char *)n, '\0', sizeof(struct nmb_name) );
703         fstrcpy(unix_name, name);
704         strupper_m(unix_name);
705         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
706         n->name_type = (unsigned int)type & 0xFF;
707         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
708 }
709
710 static BOOL do_nodestatus(const struct process_id pid,
711                           const int argc, const char **argv)
712 {
713         struct packet_struct p;
714
715         if (argc != 2) {
716                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
717                 return False;
718         }
719
720         ZERO_STRUCT(p);
721
722         p.ip = *interpret_addr2(argv[1]);
723         p.port = 137;
724         p.packet_type = NMB_PACKET;
725
726         p.packet.nmb.header.name_trn_id = 10;
727         p.packet.nmb.header.opcode = 0;
728         p.packet.nmb.header.response = False;
729         p.packet.nmb.header.nm_flags.bcast = False;
730         p.packet.nmb.header.nm_flags.recursion_available = False;
731         p.packet.nmb.header.nm_flags.recursion_desired = False;
732         p.packet.nmb.header.nm_flags.trunc = False;
733         p.packet.nmb.header.nm_flags.authoritative = False;
734         p.packet.nmb.header.rcode = 0;
735         p.packet.nmb.header.qdcount = 1;
736         p.packet.nmb.header.ancount = 0;
737         p.packet.nmb.header.nscount = 0;
738         p.packet.nmb.header.arcount = 0;
739         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
740         p.packet.nmb.question.question_type = 0x21;
741         p.packet.nmb.question.question_class = 0x1;
742
743         return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
744 }
745
746 /* A list of message type supported */
747
748 static const struct {
749         const char *name;       /* Option name */
750         BOOL (*fn)(const struct process_id pid,
751                    const int argc, const char **argv);
752         const char *help;       /* Short help text */
753 } msg_types[] = {
754         { "debug", do_debug, "Set debuglevel"  },
755         { "force-election", do_election,
756           "Force a browse election" },
757         { "ping", do_ping, "Elicit a response" },
758         { "profile", do_profile, "" },
759         { "profilelevel", do_profilelevel, "" },
760         { "debuglevel", do_debuglevel, "Display current debuglevels" },
761         { "printnotify", do_printnotify, "Send a print notify message" },
762         { "close-share", do_closeshare, "Forcibly disconnect a share" },
763         { "samsync", do_samsync, "Initiate SAM synchronisation" },
764         { "samrepl", do_samrepl, "Initiate SAM replication" },
765         { "pool-usage", do_poolusage, "Display talloc memory usage" },
766         { "dmalloc-mark", do_dmalloc_mark, "" },
767         { "dmalloc-log-changed", do_dmalloc_changed, "" },
768         { "shutdown", do_shutdown, "Shut down daemon" },
769         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
770         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
771         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
772         { "online", do_winbind_online, "Ask winbind to go into online state"},
773         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
774         { "noop", do_noop, "Do nothing" },
775         { NULL }
776 };
777
778 /* Display usage information */
779
780 static void usage(poptContext *pc)
781 {
782         int i;
783
784         poptPrintHelp(*pc, stderr, 0);
785
786         fprintf(stderr, "\n");
787         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
788                 "process ID\n");
789
790         fprintf(stderr, "\n");
791         fprintf(stderr, "<message-type> is one of:\n");
792
793         for (i = 0; msg_types[i].name; i++) 
794             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
795                     msg_types[i].help);
796
797         fprintf(stderr, "\n");
798
799         exit(1);
800 }
801
802 /* Return the pid number for a string destination */
803
804 static struct process_id parse_dest(const char *dest)
805 {
806         struct process_id result;
807         pid_t pid;
808
809         /* Zero is a special return value for broadcast smbd */
810
811         if (strequal(dest, "smbd")) {
812                 return interpret_pid("0");
813         }
814
815         /* Try self - useful for testing */
816
817         if (strequal(dest, "self")) {
818                 return pid_to_procid(sys_getpid());
819         }
820
821         /* Fix winbind typo. */
822         if (strequal(dest, "winbind")) {
823                 dest = "winbindd";
824         }
825
826         /* Check for numeric pid number */
827
828         result = interpret_pid(dest);
829
830         /* Zero isn't valid if not smbd. */
831         if (result.pid && procid_valid(&result)) {
832                 return result;
833         }
834
835         /* Look up other destinations in pidfile directory */
836
837         if ((pid = pidfile_pid(dest)) != 0) {
838                 return pid_to_procid(pid);
839         }
840
841         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
842
843         return result;
844 }       
845
846 /* Execute smbcontrol command */
847
848 static BOOL do_command(int argc, const char **argv)
849 {
850         const char *dest = argv[0], *command = argv[1];
851         struct process_id pid;
852         int i;
853
854         /* Check destination */
855
856         pid = parse_dest(dest);
857         if (!procid_valid(&pid)) {
858                 return False;
859         }
860
861         /* Check command */
862
863         for (i = 0; msg_types[i].name; i++) {
864                 if (strequal(command, msg_types[i].name))
865                         return msg_types[i].fn(pid, argc - 1, argv + 1);
866         }
867
868         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
869
870         return False;
871 }
872
873 /* Main program */
874
875 int main(int argc, const char **argv)
876 {
877         poptContext pc;
878         int opt;
879
880         static struct poptOption wbinfo_options[] = {
881                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
882                   "Set timeout value in seconds", "TIMEOUT" },
883
884                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
885                   "Use alternative configuration file", "CONFIGFILE" },
886
887                 POPT_TABLEEND
888         };
889
890         struct poptOption options[] = {
891                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
892                   "Options" },
893
894                 POPT_AUTOHELP
895                 POPT_COMMON_VERSION
896                 POPT_TABLEEND
897         };
898
899         load_case_tables();
900
901         setup_logging(argv[0],True);
902         
903         /* Parse command line arguments using popt */
904
905         pc = poptGetContext(
906                 "smbcontrol", argc, (const char **)argv, options, 0);
907
908         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
909                                "<parameters>");
910
911         if (argc == 1)
912                 usage(&pc);
913
914         while ((opt = poptGetNextOpt(pc)) != -1) {
915                 switch(opt) {
916                 case 't':       /* --timeout */
917                         argc -= 2;
918                         break;
919                 case 's':       /* --configfile */
920                         pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
921                         argc -= 2;
922                         break;
923                 default:
924                         fprintf(stderr, "Invalid option\n");
925                         poptPrintHelp(pc, stderr, 0);
926                         break;
927                 }
928         }
929
930         /* We should now have the remaining command line arguments in
931            argv.  The argc parameter should have been decremented to the
932            correct value in the above switch statement. */
933
934         argv = (const char **)poptGetArgs(pc);
935         argc--;                 /* Don't forget about argv[0] */
936
937         if (argc == 1)
938                 usage(&pc);
939
940         lp_load(dyn_CONFIGFILE,False,False,False,True);
941
942         /* Need to invert sense of return code -- samba
943          * routines mostly return True==1 for success, but
944          * shell needs 0. */ 
945         
946         return !do_command(argc, argv);
947 }