r23010: Make the output of "smbcontrol --help" match that of "smbcontrol help".
[obnox/samba/samba-obnox.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    Copyright (C) James Peach 2006
11    
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27 #include "includes.h"
28
29 #if HAVE_LIBUNWIND_H
30 #include <libunwind.h>
31 #endif
32
33 #if HAVE_LIBUNWIND_PTRACE_H
34 #include <libunwind-ptrace.h>
35 #endif
36
37 #if HAVE_SYS_PTRACE_H
38 #include <sys/ptrace.h>
39 #endif
40
41 /* Default timeout value when waiting for replies (in seconds) */
42
43 #define DEFAULT_TIMEOUT 10
44
45 static int timeout = DEFAULT_TIMEOUT;
46 static int num_replies;         /* Used by message callback fns */
47
48 /* Send a message to a destination pid.  Zero means broadcast smbd. */
49
50 static BOOL send_message(struct messaging_context *msg_ctx,
51                          struct server_id pid, int msg_type,
52                          const void *buf, int len,
53                          BOOL duplicates)
54 {
55         BOOL ret;
56         int n_sent = 0;
57
58         if (procid_to_pid(&pid) != 0)
59                 return NT_STATUS_IS_OK(
60                         messaging_send_buf(msg_ctx, pid, msg_type,
61                                            (uint8 *)buf, len));
62
63         ret = message_send_all(msg_ctx, msg_type, buf, len, duplicates,
64                                &n_sent);
65         DEBUG(10,("smbcontrol/send_message: broadcast message to "
66                   "%d processes\n", n_sent));
67         
68         return ret;
69 }
70
71 /* Wait for one or more reply messages */
72
73 static void wait_replies(struct messaging_context *msg_ctx,
74                          BOOL multiple_replies)
75 {
76         time_t start_time = time(NULL);
77
78         /* Wait around a bit.  This is pretty disgusting - we have to
79            busy-wait here as there is no nicer way to do it. */
80
81         do {
82                 message_dispatch();
83                 event_loop_once(messaging_event_context(msg_ctx));
84                 if (num_replies > 0 && !multiple_replies)
85                         break;
86                 sleep(1);
87         } while (timeout - (time(NULL) - start_time) > 0);
88 }
89
90 /* Message handler callback that displays the PID and a string on stdout */
91
92 static void print_pid_string_cb(struct messaging_context *msg,
93                                 void *private_data, 
94                                 uint32_t msg_type, 
95                                 struct server_id pid,
96                                 DATA_BLOB *data)
97 {
98         printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
99                (int)data->length, (const char *)data->data);
100         num_replies++;
101 }
102
103 /* Message handler callback that displays a string on stdout */
104
105 static void print_string_cb(struct messaging_context *msg,
106                             void *private_data, 
107                             uint32_t msg_type, 
108                             struct server_id pid,
109                             DATA_BLOB *data)
110 {
111         printf("%.*s", (int)data->length, (const char *)data->data);
112         num_replies++;
113 }
114
115 /* Send no message.  Useful for testing. */
116
117 static BOOL do_noop(struct messaging_context *msg_ctx,
118                     const struct server_id pid,
119                     const int argc, const char **argv)
120 {
121         if (argc != 1) {
122                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
123                 return False;
124         }
125
126         /* Move along, nothing to see here */
127
128         return True;
129 }
130
131 /* Send a debug string */
132
133 static BOOL do_debug(struct messaging_context *msg_ctx,
134                      const struct server_id pid,
135                      const int argc, const char **argv)
136 {
137         if (argc != 2) {
138                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
139                         "<debug-string>\n");
140                 return False;
141         }
142
143         return send_message(msg_ctx,
144                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
145 }
146
147 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
148
149 /* Return the name of a process given it's PID. This will only work on Linux,
150  * but that's probably moot since this whole stack tracing implementatino is
151  * Linux-specific anyway.
152  */
153 static const char * procname(pid_t pid, char * buf, size_t bufsz)
154 {
155         char path[64];
156         FILE * fp;
157
158         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
159                 (unsigned long long)pid);
160         if ((fp = fopen(path, "r")) == NULL) {
161                 return NULL;
162         }
163
164         fgets(buf, bufsz, fp);
165
166         fclose(fp);
167         return buf;
168 }
169
170 static void print_stack_trace(pid_t pid, int * count)
171 {
172         void *              pinfo = NULL;
173         unw_addr_space_t    aspace = NULL;
174         unw_cursor_t        cursor;
175         unw_word_t          ip, sp;
176
177         char                nbuf[256];
178         unw_word_t          off;
179
180         int ret;
181
182         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
183                 fprintf(stderr,
184                         "Failed to attach to process %llu: %s\n",
185                         (unsigned long long)pid, strerror(errno));
186                 return;
187         }
188
189         /* Wait until the attach is complete. */
190         waitpid(pid, NULL, 0);
191
192         if (((pinfo = _UPT_create(pid)) == NULL) ||
193             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
194                 /* Probably out of memory. */
195                 fprintf(stderr,
196                         "Unable to initialize stack unwind for process %llu\n",
197                         (unsigned long long)pid);
198                 goto cleanup;
199         }
200
201         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
202                 fprintf(stderr,
203                         "Unable to unwind stack for process %llu: %s\n",
204                         (unsigned long long)pid, unw_strerror(ret));
205                 goto cleanup;
206         }
207
208         if (*count > 0) {
209                 printf("\n");
210         }
211
212         if (procname(pid, nbuf, sizeof(nbuf))) {
213                 printf("Stack trace for process %llu (%s):\n",
214                         (unsigned long long)pid, nbuf);
215         } else {
216                 printf("Stack trace for process %llu:\n",
217                         (unsigned long long)pid);
218         }
219
220         while (unw_step(&cursor) > 0) {
221                 ip = sp = off = 0;
222                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
223                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
224
225                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
226                 if (ret != 0 && ret != -UNW_ENOMEM) {
227                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
228                 }
229                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
230                         nbuf, (long long)off, (long long)ip,
231                         (long long)sp);
232         }
233
234         (*count)++;
235
236 cleanup:
237         if (aspace) {
238                 unw_destroy_addr_space(aspace);
239         }
240
241         if (pinfo) {
242                 _UPT_destroy(pinfo);
243         }
244
245         ptrace(PTRACE_DETACH, pid, NULL, NULL);
246 }
247
248 static int stack_trace_connection(TDB_CONTEXT * tdb, 
249                                   const struct connections_key *key,
250                                   const struct connections_data *conn,
251 {
252         print_stack_trace(procid_to_pid(&conn->pid), (int *)priv);
253
254         return 0;
255 }
256
257 static BOOL do_daemon_stack_trace(struct messaging_context *msg_ctx,
258                                   const struct server_id pid,
259                        const int argc, const char **argv)
260 {
261         fprintf(stderr,
262                 "Daemon stack tracing is not supported on this platform\n");
263         return False;
264
265         pid_t   dest;
266         int     count = 0;
267
268         if (argc != 1) {
269                 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
270                 return False;
271         }
272
273         dest = procid_to_pid(&pid);
274
275         if (dest != 0) {
276                 /* It would be nice to be able to make sure that this PID is
277                  * the PID of a smbd/winbind/nmbd process, not some random PID
278                  * the user liked the look of. It doesn't seem like it's worth
279                  * the effort at the moment, however.
280                  */
281                 print_stack_trace(dest, &count);
282         } else {
283                 connections_traverse(stack_trace_connection, &count);
284         }
285
286         return True;
287 }
288
289 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
290
291 static BOOL do_daemon_stack_trace(struct messaging_context *msg_ctx,
292                                   const struct server_id pid,
293                        const int argc, const char **argv)
294 {
295         fprintf(stderr,
296                 "Daemon stack tracing is not supported on this platform\n");
297         return False;
298 }
299
300 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
301
302 /* Inject a fault (fatal signal) into a running smbd */
303
304 static BOOL do_inject_fault(struct messaging_context *msg_ctx,
305                             const struct server_id pid,
306                        const int argc, const char **argv)
307 {
308         if (argc != 2) {
309                 fprintf(stderr, "Usage: smbcontrol <dest> inject "
310                         "<bus|hup|term|internal|segv>\n");
311                 return False;
312         }
313
314 #ifndef DEVELOPER
315         fprintf(stderr, "Fault injection is only available in "
316                 "developer builds\n");
317         return False;
318 #else /* DEVELOPER */
319         {
320                 int sig = 0;
321
322                 if (strcmp(argv[1], "bus") == 0) {
323                         sig = SIGBUS;
324                 } else if (strcmp(argv[1], "hup") == 0) {
325                         sig = SIGHUP;
326                 } else if (strcmp(argv[1], "term") == 0) {
327                         sig = SIGTERM;
328                 } else if (strcmp(argv[1], "segv") == 0) {
329                         sig = SIGSEGV;
330                 } else if (strcmp(argv[1], "internal") == 0) {
331                         /* Force an internal error, ie. an unclean exit. */
332                         sig = -1;
333                 } else {
334                         fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
335                         return False;
336                 }
337
338                 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
339                                     &sig, sizeof(int), False);
340         }
341 #endif /* DEVELOPER */
342 }
343
344 /* Force a browser election */
345
346 static BOOL do_election(struct messaging_context *msg_ctx,
347                         const struct server_id pid,
348                         const int argc, const char **argv)
349 {
350         if (argc != 1) {
351                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
352                 return False;
353         }
354
355         return send_message(msg_ctx,
356                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
357 }
358
359 /* Ping a samba daemon process */
360
361 static void pong_cb(struct messaging_context *msg,
362                     void *private_data, 
363                     uint32_t msg_type, 
364                     struct server_id pid,
365                     DATA_BLOB *data)
366 {
367         char *src_string = procid_str(NULL, &pid);
368         printf("PONG from pid %s\n", src_string);
369         TALLOC_FREE(src_string);
370         num_replies++;
371 }
372
373 static BOOL do_ping(struct messaging_context *msg_ctx,
374                     const struct server_id pid,
375                     const int argc, const char **argv)
376 {
377         if (argc != 1) {
378                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
379                 return False;
380         }
381
382         /* Send a message and register our interest in a reply */
383
384         if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0, False))
385                 return False;
386
387         messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
388
389         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
390
391         /* No replies were received within the timeout period */
392
393         if (num_replies == 0)
394                 printf("No replies received\n");
395
396         messaging_deregister(msg_ctx, MSG_PONG, NULL);
397
398         return num_replies;
399 }
400
401 /* Set profiling options */
402
403 static BOOL do_profile(struct messaging_context *msg_ctx,
404                        const struct server_id pid,
405                        const int argc, const char **argv)
406 {
407         int v;
408
409         if (argc != 2) {
410                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
411                         "<off|count|on|flush>\n");
412                 return False;
413         }
414
415         if (strcmp(argv[1], "off") == 0) {
416                 v = 0;
417         } else if (strcmp(argv[1], "count") == 0) {
418                 v = 1;
419         } else if (strcmp(argv[1], "on") == 0) {
420                 v = 2;
421         } else if (strcmp(argv[1], "flush") == 0) {
422                 v = 3;
423         } else {
424                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
425                 return False;
426         }
427
428         return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int), False);
429 }
430
431 /* Return the profiling level */
432
433 static void profilelevel_cb(struct messaging_context *msg_ctx,
434                             void *private_data, 
435                             uint32_t msg_type, 
436                             struct server_id pid,
437                             DATA_BLOB *data)
438 {
439         int level;
440         const char *s;
441
442         num_replies++;
443
444         if (data->length != sizeof(int)) {
445                 fprintf(stderr, "invalid message length %ld returned\n", 
446                         (unsigned long)data->length);
447                 return;
448         }
449
450         memcpy(&level, data->data, sizeof(int));
451
452         switch (level) {
453         case 0:
454                 s = "not enabled";
455                 break;
456         case 1:
457                 s = "off";
458                 break;
459         case 3:
460                 s = "count only";
461                 break;
462         case 7:
463                 s = "count and time";
464                 break;
465         default:
466                 s = "BOGUS";
467                 break;
468         }
469         
470         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
471 }
472
473 static void profilelevel_rqst(struct messaging_context *msg_ctx,
474                               void *private_data, 
475                               uint32_t msg_type, 
476                               struct server_id pid,
477                               DATA_BLOB *data)
478 {
479         int v = 0;
480
481         /* Send back a dummy reply */
482
483         send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
484 }
485
486 static BOOL do_profilelevel(struct messaging_context *msg_ctx,
487                             const struct server_id pid,
488                             const int argc, const char **argv)
489 {
490         if (argc != 1) {
491                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
492                 return False;
493         }
494
495         /* Send a message and register our interest in a reply */
496
497         if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
498                 return False;
499
500         messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
501         messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
502                            profilelevel_rqst);
503
504         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
505
506         /* No replies were received within the timeout period */
507
508         if (num_replies == 0)
509                 printf("No replies received\n");
510
511         messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
512
513         return num_replies;
514 }
515
516 /* Display debug level settings */
517
518 static BOOL do_debuglevel(struct messaging_context *msg_ctx,
519                           const struct server_id pid,
520                           const int argc, const char **argv)
521 {
522         if (argc != 1) {
523                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
524                 return False;
525         }
526
527         /* Send a message and register our interest in a reply */
528
529         if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
530                 return False;
531
532         messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
533
534         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
535
536         /* No replies were received within the timeout period */
537
538         if (num_replies == 0)
539                 printf("No replies received\n");
540
541         messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
542
543         return num_replies;
544 }
545
546 /* Send a print notify message */
547
548 static BOOL do_printnotify(struct messaging_context *msg_ctx,
549                            const struct server_id pid,
550                            const int argc, const char **argv)
551 {
552         const char *cmd;
553
554         /* Check for subcommand */
555
556         if (argc == 1) {
557                 fprintf(stderr, "Must specify subcommand:\n");
558                 fprintf(stderr, "\tqueuepause <printername>\n");
559                 fprintf(stderr, "\tqueueresume <printername>\n");
560                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
561                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
562                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
563                 fprintf(stderr, "\tprinter <printername> <comment|port|"
564                         "driver> <value>\n");
565                 
566                 return False;
567         }
568
569         cmd = argv[1];
570
571         if (strcmp(cmd, "queuepause") == 0) {
572
573                 if (argc != 3) {
574                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
575                                 " queuepause <printername>\n");
576                         return False;
577                 }
578                 
579                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
580
581                 goto send;
582
583         } else if (strcmp(cmd, "queueresume") == 0) {
584
585                 if (argc != 3) {
586                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
587                                 " queuereume <printername>\n");
588                         return False;
589                 }
590                 
591                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
592
593                 goto send;
594
595         } else if (strcmp(cmd, "jobpause") == 0) {
596                 int jobid;
597
598                 if (argc != 4) {
599                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
600                                 " jobpause <printername> <unix-jobid>\n");
601                         return False;
602                 }
603
604                 jobid = atoi(argv[3]);
605
606                 notify_job_status_byname(
607                         argv[2], jobid, JOB_STATUS_PAUSED, 
608                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
609
610                 goto send;
611
612         } else if (strcmp(cmd, "jobresume") == 0) {
613                 int jobid;
614
615                 if (argc != 4) {
616                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
617                                 " jobpause <printername> <unix-jobid>\n");
618                         return False;
619                 }
620
621                 jobid = atoi(argv[3]);
622
623                 notify_job_status_byname(
624                         argv[2], jobid, JOB_STATUS_QUEUED, 
625                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
626
627                 goto send;
628
629         } else if (strcmp(cmd, "jobdelete") == 0) {
630                 int jobid;
631
632                 if (argc != 4) {
633                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
634                                 " jobpause <printername> <unix-jobid>\n");
635                         return False;
636                 }
637
638                 jobid = atoi(argv[3]);
639
640                 notify_job_status_byname(
641                         argv[2], jobid, JOB_STATUS_DELETING,
642                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
643                 
644                 notify_job_status_byname(
645                         argv[2], jobid, JOB_STATUS_DELETING|
646                         JOB_STATUS_DELETED,
647                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
648
649                 goto send;
650
651         } else if (strcmp(cmd, "printer") == 0) {
652                 uint32 attribute;
653                 
654                 if (argc != 5) {
655                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
656                                 "printer <printername> <comment|port|driver> "
657                                 "<value>\n");
658                         return False;
659                 }
660
661                 if (strcmp(argv[3], "comment") == 0) {
662                         attribute = PRINTER_NOTIFY_COMMENT;
663                 } else if (strcmp(argv[3], "port") == 0) {
664                         attribute = PRINTER_NOTIFY_PORT_NAME;
665                 } else if (strcmp(argv[3], "driver") == 0) {
666                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
667                 } else {
668                         fprintf(stderr, "Invalid printer command '%s'\n",
669                                 argv[3]);
670                         return False;
671                 }
672
673                 notify_printer_byname(argv[2], attribute,
674                                       CONST_DISCARD(char *, argv[4]));
675
676                 goto send;
677         }
678
679         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
680         return False;
681
682 send:
683         print_notify_send_messages(msg_ctx, 0);
684         return True;
685 }
686
687 /* Close a share */
688
689 static BOOL do_closeshare(struct messaging_context *msg_ctx,
690                           const struct server_id pid,
691                           const int argc, const char **argv)
692 {
693         if (argc != 2) {
694                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
695                         "<sharename>\n");
696                 return False;
697         }
698
699         return send_message(msg_ctx,
700                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
701 }
702
703 /* Force a SAM synchronisation */
704
705 static BOOL do_samsync(struct messaging_context *msg_ctx,
706                        const struct server_id pid,
707                        const int argc, const char **argv)
708 {
709         if (argc != 1) {
710                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
711                 return False;
712         }
713
714         return send_message(msg_ctx,
715                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
716 }
717
718 /* Force a SAM replication */
719
720 static BOOL do_samrepl(struct messaging_context *msg_ctx,
721                        const struct server_id pid,
722                        const int argc, const char **argv)
723 {
724         if (argc != 1) {
725                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
726                 return False;
727         }
728
729         return send_message(msg_ctx,
730                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
731 }
732
733 /* Display talloc pool usage */
734
735 static BOOL do_poolusage(struct messaging_context *msg_ctx,
736                          const struct server_id pid,
737                          const int argc, const char **argv)
738 {
739         if (argc != 1) {
740                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
741                 return False;
742         }
743
744         messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
745
746         /* Send a message and register our interest in a reply */
747
748         if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
749                 return False;
750
751         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
752
753         /* No replies were received within the timeout period */
754
755         if (num_replies == 0)
756                 printf("No replies received\n");
757
758         messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
759
760         return num_replies;
761 }
762
763 /* Perform a dmalloc mark */
764
765 static BOOL do_dmalloc_mark(struct messaging_context *msg_ctx,
766                             const struct server_id pid,
767                             const int argc, const char **argv)
768 {
769         if (argc != 1) {
770                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
771                 return False;
772         }
773
774         return send_message(msg_ctx,
775                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
776 }
777
778 /* Perform a dmalloc changed */
779
780 static BOOL do_dmalloc_changed(struct messaging_context *msg_ctx,
781                                const struct server_id pid,
782                                const int argc, const char **argv)
783 {
784         if (argc != 1) {
785                 fprintf(stderr, "Usage: smbcontrol <dest> "
786                         "dmalloc-log-changed\n");
787                 return False;
788         }
789
790         return send_message(msg_ctx,
791                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
792 }
793
794 /* Shutdown a server process */
795
796 static BOOL do_shutdown(struct messaging_context *msg_ctx,
797                         const struct server_id pid,
798                         const int argc, const char **argv)
799 {
800         if (argc != 1) {
801                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
802                 return False;
803         }
804
805         return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0, False);
806 }
807
808 /* Notify a driver upgrade */
809
810 static BOOL do_drvupgrade(struct messaging_context *msg_ctx,
811                           const struct server_id pid,
812                           const int argc, const char **argv)
813 {
814         if (argc != 2) {
815                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
816                         "<driver-name>\n");
817                 return False;
818         }
819
820         return send_message(msg_ctx,
821                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
822 }
823
824 static BOOL do_winbind_online(struct messaging_context *msg_ctx,
825                               const struct server_id pid,
826                              const int argc, const char **argv)
827 {
828         TDB_CONTEXT *tdb;
829
830         if (argc != 1) {
831                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
832                 return False;
833         }
834
835         if (!lp_winbind_offline_logon()) {
836                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
837                         "be set in the [global] section of smb.conf for this "
838                         "command to be allowed.\n");
839                 return False;
840         }
841
842         /* Remove the entry in the winbindd_cache tdb to tell a later
843            starting winbindd that we're online. */
844
845         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
846         if (!tdb) {
847                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
848                         lock_path("winbindd_cache.tdb"));
849                 return False;
850         }
851
852         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
853         tdb_close(tdb);
854
855         return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0, False);
856 }
857
858 static BOOL do_winbind_offline(struct messaging_context *msg_ctx,
859                                const struct server_id pid,
860                              const int argc, const char **argv)
861 {
862         TDB_CONTEXT *tdb;
863         BOOL ret = False;
864         int retry = 0;
865
866         if (argc != 1) {
867                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
868                 return False;
869         }
870
871         if (!lp_winbind_offline_logon()) {
872                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
873                         "be set in the [global] section of smb.conf for this "
874                         "command to be allowed.\n");
875                 return False;
876         }
877
878         /* Create an entry in the winbindd_cache tdb to tell a later
879            starting winbindd that we're offline. We may actually create
880            it here... */
881
882         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
883                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
884                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
885
886         if (!tdb) {
887                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
888                         lock_path("winbindd_cache.tdb"));
889                 return False;
890         }
891
892         /* There's a potential race condition that if a child
893            winbindd detects a domain is online at the same time
894            we're trying to tell it to go offline that it might 
895            delete the record we add between us adding it and
896            sending the message. Minimize this by retrying up to
897            5 times. */
898
899         for (retry = 0; retry < 5; retry++) {
900                 TDB_DATA d;
901                 uint8 buf[4];
902
903                 ZERO_STRUCT(d);
904
905                 SIVAL(buf, 0, time(NULL));
906                 d.dptr = buf;
907                 d.dsize = 4;
908
909                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
910
911                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
912                                    NULL, 0, False);
913
914                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
915                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
916         
917                 if (!d.dptr || d.dsize != 4) {
918                         SAFE_FREE(d.dptr);
919                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
920                 } else {
921                         SAFE_FREE(d.dptr);
922                         break;
923                 }
924         }
925
926         tdb_close(tdb);
927         return ret;
928 }
929
930 static BOOL do_winbind_onlinestatus(struct messaging_context *msg_ctx,
931                                     const struct server_id pid,
932                                     const int argc, const char **argv)
933 {
934         struct server_id myid;
935
936         myid = pid_to_procid(sys_getpid());
937
938         if (argc != 1) {
939                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
940                 return False;
941         }
942
943         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
944                            print_pid_string_cb);
945
946         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
947                           sizeof(myid), False))
948                 return False;
949
950         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
951
952         /* No replies were received within the timeout period */
953
954         if (num_replies == 0)
955                 printf("No replies received\n");
956
957         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
958
959         return num_replies;
960 }
961
962
963 static BOOL do_reload_config(struct messaging_context *msg_ctx,
964                              const struct server_id pid,
965                              const int argc, const char **argv)
966 {
967         if (argc != 1) {
968                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
969                 return False;
970         }
971
972         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED,
973                             NULL, 0, False);
974 }
975
976 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
977 {
978         fstring unix_name;
979         memset( (char *)n, '\0', sizeof(struct nmb_name) );
980         fstrcpy(unix_name, name);
981         strupper_m(unix_name);
982         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
983         n->name_type = (unsigned int)type & 0xFF;
984         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
985 }
986
987 static BOOL do_nodestatus(struct messaging_context *msg_ctx,
988                           const struct server_id pid,
989                           const int argc, const char **argv)
990 {
991         struct packet_struct p;
992
993         if (argc != 2) {
994                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
995                 return False;
996         }
997
998         ZERO_STRUCT(p);
999
1000         p.ip = *interpret_addr2(argv[1]);
1001         p.port = 137;
1002         p.packet_type = NMB_PACKET;
1003
1004         p.packet.nmb.header.name_trn_id = 10;
1005         p.packet.nmb.header.opcode = 0;
1006         p.packet.nmb.header.response = False;
1007         p.packet.nmb.header.nm_flags.bcast = False;
1008         p.packet.nmb.header.nm_flags.recursion_available = False;
1009         p.packet.nmb.header.nm_flags.recursion_desired = False;
1010         p.packet.nmb.header.nm_flags.trunc = False;
1011         p.packet.nmb.header.nm_flags.authoritative = False;
1012         p.packet.nmb.header.rcode = 0;
1013         p.packet.nmb.header.qdcount = 1;
1014         p.packet.nmb.header.ancount = 0;
1015         p.packet.nmb.header.nscount = 0;
1016         p.packet.nmb.header.arcount = 0;
1017         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1018         p.packet.nmb.question.question_type = 0x21;
1019         p.packet.nmb.question.question_class = 0x1;
1020
1021         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p),
1022                             False);
1023 }
1024
1025 /* A list of message type supported */
1026
1027 static const struct {
1028         const char *name;       /* Option name */
1029         BOOL (*fn)(struct messaging_context *msg_ctx,
1030                    const struct server_id pid,
1031                    const int argc, const char **argv);
1032         const char *help;       /* Short help text */
1033 } msg_types[] = {
1034         { "debug", do_debug, "Set debuglevel"  },
1035         { "force-election", do_election,
1036           "Force a browse election" },
1037         { "ping", do_ping, "Elicit a response" },
1038         { "profile", do_profile, "" },
1039         { "inject", do_inject_fault,
1040             "Inject a fatal signal into a running smbd"},
1041         { "stacktrace", do_daemon_stack_trace,
1042             "Display a stack trace of a daemon" },
1043         { "profilelevel", do_profilelevel, "" },
1044         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1045         { "printnotify", do_printnotify, "Send a print notify message" },
1046         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1047         { "samsync", do_samsync, "Initiate SAM synchronisation" },
1048         { "samrepl", do_samrepl, "Initiate SAM replication" },
1049         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1050         { "dmalloc-mark", do_dmalloc_mark, "" },
1051         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1052         { "shutdown", do_shutdown, "Shut down daemon" },
1053         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1054         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1055         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1056         { "online", do_winbind_online, "Ask winbind to go into online state"},
1057         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1058         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1059         { "noop", do_noop, "Do nothing" },
1060         { NULL }
1061 };
1062
1063 /* Display usage information */
1064
1065 static void usage(poptContext pc)
1066 {
1067         int i;
1068
1069         poptPrintHelp(pc, stderr, 0);
1070
1071         fprintf(stderr, "\n");
1072         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1073                 "process ID\n");
1074
1075         fprintf(stderr, "\n");
1076         fprintf(stderr, "<message-type> is one of:\n");
1077
1078         for (i = 0; msg_types[i].name; i++) 
1079             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1080                     msg_types[i].help);
1081
1082         fprintf(stderr, "\n");
1083
1084         exit(1);
1085 }
1086
1087 /* Return the pid number for a string destination */
1088
1089 static struct server_id parse_dest(const char *dest)
1090 {
1091         struct server_id result = {-1};
1092         pid_t pid;
1093
1094         /* Zero is a special return value for broadcast smbd */
1095
1096         if (strequal(dest, "smbd")) {
1097                 return interpret_pid("0");
1098         }
1099
1100         /* Try self - useful for testing */
1101
1102         if (strequal(dest, "self")) {
1103                 return pid_to_procid(sys_getpid());
1104         }
1105
1106         /* Fix winbind typo. */
1107         if (strequal(dest, "winbind")) {
1108                 dest = "winbindd";
1109         }
1110
1111         
1112         if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1113                 /* Check for numeric pid number */
1114
1115                 result = interpret_pid(dest);
1116
1117                 /* Zero isn't valid if not smbd. */
1118                 if (result.pid && procid_valid(&result)) {
1119                         return result;
1120                 }
1121         }
1122
1123         /* Look up other destinations in pidfile directory */
1124
1125         if ((pid = pidfile_pid(dest)) != 0) {
1126                 return pid_to_procid(pid);
1127         }
1128
1129         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1130
1131         return result;
1132 }       
1133
1134 /* Execute smbcontrol command */
1135
1136 static BOOL do_command(struct messaging_context *msg_ctx,
1137                        int argc, const char **argv)
1138 {
1139         const char *dest = argv[0], *command = argv[1];
1140         struct server_id pid;
1141         int i;
1142
1143         /* Check destination */
1144
1145         pid = parse_dest(dest);
1146         if (!procid_valid(&pid)) {
1147                 return False;
1148         }
1149
1150         /* Check command */
1151
1152         for (i = 0; msg_types[i].name; i++) {
1153                 if (strequal(command, msg_types[i].name))
1154                         return msg_types[i].fn(msg_ctx, pid,
1155                                                argc - 1, argv + 1);
1156         }
1157
1158         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1159
1160         return False;
1161 }
1162
1163 static void smbcontrol_help(poptContext pc,
1164                     enum poptCallbackReason preason,
1165                     struct poptOption * poption,
1166                     const char * parg,
1167                     void * pdata)
1168 {
1169         if (poption->shortName != '?') {
1170                 poptPrintUsage(pc, stdout, 0);
1171         } else {
1172                 usage(pc);
1173         }
1174
1175         exit(0);
1176 }
1177
1178 struct poptOption help_options[] = {
1179         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1180           NULL, NULL },
1181         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1182         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1183         { NULL }
1184 } ;
1185
1186 /* Main program */
1187
1188 int main(int argc, const char **argv)
1189 {
1190         poptContext pc;
1191         int opt;
1192         struct event_context *evt_ctx;
1193         struct messaging_context *msg_ctx;
1194
1195         static struct poptOption long_options[] = {
1196                 /* POPT_AUTOHELP */
1197                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1198                                         0, "Help options:", NULL },
1199                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1200                   "Set timeout value in seconds", "TIMEOUT" },
1201
1202                 POPT_COMMON_SAMBA
1203                 POPT_TABLEEND
1204         };
1205
1206         load_case_tables();
1207
1208         setup_logging(argv[0],True);
1209         
1210         /* Parse command line arguments using popt */
1211
1212         pc = poptGetContext(
1213                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1214
1215         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1216                                "<parameters>");
1217
1218         if (argc == 1)
1219                 usage(pc);
1220
1221         while ((opt = poptGetNextOpt(pc)) != -1) {
1222                 switch(opt) {
1223                 case 't':       /* --timeout */
1224                         break;
1225                 default:
1226                         fprintf(stderr, "Invalid option\n");
1227                         poptPrintHelp(pc, stderr, 0);
1228                         break;
1229                 }
1230         }
1231
1232         /* We should now have the remaining command line arguments in
1233            argv.  The argc parameter should have been decremented to the
1234            correct value in the above switch statement. */
1235
1236         argv = (const char **)poptGetArgs(pc);
1237         argc = 0;
1238         while (argv[argc] != NULL) {
1239                 argc++;
1240         }
1241
1242         if (argc == 1)
1243                 usage(pc);
1244
1245         lp_load(dyn_CONFIGFILE,False,False,False,True);
1246
1247         /* Need to invert sense of return code -- samba
1248          * routines mostly return True==1 for success, but
1249          * shell needs 0. */ 
1250         
1251         if (!(evt_ctx = event_context_init(NULL)) ||
1252             !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1253                 fprintf(stderr, "could not init messaging context\n");
1254                 exit(1);
1255         }
1256         
1257         return !do_command(msg_ctx, argc, argv);
1258 }