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