winbind: Add smbcontrol disconnect-dc
[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    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 3 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, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "system/filesys.h"
28 #include "lib/util/server_id.h"
29 #include "popt_common.h"
30 #include "librpc/gen_ndr/spoolss.h"
31 #include "nt_printing.h"
32 #include "printing/notify.h"
33 #include "libsmb/nmblib.h"
34 #include "messages.h"
35 #include "util_tdb.h"
36 #include "../lib/util/pidfile.h"
37 #include "serverid.h"
38
39 #if HAVE_LIBUNWIND_H
40 #include <libunwind.h>
41 #endif
42
43 #if HAVE_LIBUNWIND_PTRACE_H
44 #include <libunwind-ptrace.h>
45 #endif
46
47 #if HAVE_SYS_PTRACE_H
48 #include <sys/ptrace.h>
49 #endif
50
51 /* Default timeout value when waiting for replies (in seconds) */
52
53 #define DEFAULT_TIMEOUT 10
54
55 static int timeout = DEFAULT_TIMEOUT;
56 static int num_replies;         /* Used by message callback fns */
57
58 /* Send a message to a destination pid.  Zero means broadcast smbd. */
59
60 static bool send_message(struct messaging_context *msg_ctx,
61                          struct server_id pid, int msg_type,
62                          const void *buf, int len)
63 {
64         if (procid_to_pid(&pid) != 0)
65                 return NT_STATUS_IS_OK(
66                         messaging_send_buf(msg_ctx, pid, msg_type,
67                                            (const uint8_t *)buf, len));
68
69         messaging_send_all(msg_ctx, msg_type, buf, len);
70
71         return true;
72 }
73
74 static void smbcontrol_timeout(struct tevent_context *event_ctx,
75                                struct tevent_timer *te,
76                                struct timeval now,
77                                void *private_data)
78 {
79         bool *timed_out = (bool *)private_data;
80         TALLOC_FREE(te);
81         *timed_out = True;
82 }
83
84 /* Wait for one or more reply messages */
85
86 static void wait_replies(struct tevent_context *ev_ctx,
87                          struct messaging_context *msg_ctx,
88                          bool multiple_replies)
89 {
90         struct tevent_timer *te;
91         bool timed_out = False;
92
93         te = tevent_add_timer(ev_ctx, NULL,
94                               timeval_current_ofs(timeout, 0),
95                               smbcontrol_timeout, (void *)&timed_out);
96         if (te == NULL) {
97                 DEBUG(0, ("tevent_add_timer failed\n"));
98                 return;
99         }
100
101         while (!timed_out) {
102                 int ret;
103                 if (num_replies > 0 && !multiple_replies)
104                         break;
105                 ret = tevent_loop_once(ev_ctx);
106                 if (ret != 0) {
107                         break;
108                 }
109         }
110 }
111
112 /* Message handler callback that displays the PID and a string on stdout */
113
114 static void print_pid_string_cb(struct messaging_context *msg,
115                                 void *private_data, 
116                                 uint32_t msg_type, 
117                                 struct server_id pid,
118                                 DATA_BLOB *data)
119 {
120         struct server_id_buf pidstr;
121
122         printf("PID %s: %.*s", server_id_str_buf(pid, &pidstr),
123                (int)data->length, (const char *)data->data);
124         num_replies++;
125 }
126
127 /* Message handler callback that displays a string on stdout */
128
129 static void print_string_cb(struct messaging_context *msg,
130                             void *private_data, 
131                             uint32_t msg_type, 
132                             struct server_id pid,
133                             DATA_BLOB *data)
134 {
135         printf("%*s", (int)data->length, (const char *)data->data);
136         num_replies++;
137 }
138
139 /* Send no message.  Useful for testing. */
140
141 static bool do_noop(struct tevent_context *ev_ctx,
142                     struct messaging_context *msg_ctx,
143                     const struct server_id pid,
144                     const int argc, const char **argv)
145 {
146         if (argc != 1) {
147                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
148                 return False;
149         }
150
151         /* Move along, nothing to see here */
152
153         return True;
154 }
155
156 /* Send a debug string */
157
158 static bool do_debug(struct tevent_context *ev_ctx,
159                      struct messaging_context *msg_ctx,
160                      const struct server_id pid,
161                      const int argc, const char **argv)
162 {
163         if (argc != 2) {
164                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
165                         "<debug-string>\n");
166                 return False;
167         }
168
169         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
170                             strlen(argv[1]) + 1);
171 }
172
173
174 static bool do_idmap(struct tevent_context *ev,
175                      struct messaging_context *msg_ctx,
176                      const struct server_id pid,
177                      const int argc, const char **argv)
178 {
179         static const char* usage = "Usage: "
180                 "smbcontrol <dest> idmap <cmd> [arg]\n"
181                 "\tcmd:"
182                 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
183                 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
184         const char* arg = NULL;
185         int arglen = 0;
186         int msg_type;
187
188         switch (argc) {
189         case 2:
190                 break;
191         case 3:
192                 arg = argv[2];
193                 arglen = strlen(arg) + 1;
194                 break;
195         default:
196                 fprintf(stderr, "%s", usage);
197                 return false;
198         }
199
200         if (strcmp(argv[1], "delete") == 0) {
201                 msg_type = ID_CACHE_DELETE;
202         }
203         else if (strcmp(argv[1], "kill") == 0) {
204                 msg_type = ID_CACHE_KILL;
205         }
206         else if (strcmp(argv[1], "help") == 0) {
207                 fprintf(stdout, "%s", usage);
208                 return true;
209         }
210         else {
211                 fprintf(stderr, "%s", usage);
212                 return false;
213         }
214
215         return send_message(msg_ctx, pid, msg_type, arg, arglen);
216 }
217
218
219 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
220
221 /* Return the name of a process given it's PID. This will only work on Linux,
222  * but that's probably moot since this whole stack tracing implementation is
223  * Linux-specific anyway.
224  */
225 static const char * procname(pid_t pid, char * buf, size_t bufsz)
226 {
227         char path[64];
228         FILE * fp;
229
230         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
231                 (unsigned long long)pid);
232         if ((fp = fopen(path, "r")) == NULL) {
233                 return NULL;
234         }
235
236         fgets(buf, bufsz, fp);
237
238         fclose(fp);
239         return buf;
240 }
241
242 static void print_stack_trace(pid_t pid, int * count)
243 {
244         void *              pinfo = NULL;
245         unw_addr_space_t    aspace = NULL;
246         unw_cursor_t        cursor;
247         unw_word_t          ip, sp;
248
249         char                nbuf[256];
250         unw_word_t          off;
251
252         int ret;
253
254         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
255                 fprintf(stderr,
256                         "Failed to attach to process %llu: %s\n",
257                         (unsigned long long)pid, strerror(errno));
258                 return;
259         }
260
261         /* Wait until the attach is complete. */
262         waitpid(pid, NULL, 0);
263
264         if (((pinfo = _UPT_create(pid)) == NULL) ||
265             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
266                 /* Probably out of memory. */
267                 fprintf(stderr,
268                         "Unable to initialize stack unwind for process %llu\n",
269                         (unsigned long long)pid);
270                 goto cleanup;
271         }
272
273         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
274                 fprintf(stderr,
275                         "Unable to unwind stack for process %llu: %s\n",
276                         (unsigned long long)pid, unw_strerror(ret));
277                 goto cleanup;
278         }
279
280         if (*count > 0) {
281                 printf("\n");
282         }
283
284         if (procname(pid, nbuf, sizeof(nbuf))) {
285                 printf("Stack trace for process %llu (%s):\n",
286                         (unsigned long long)pid, nbuf);
287         } else {
288                 printf("Stack trace for process %llu:\n",
289                         (unsigned long long)pid);
290         }
291
292         while (unw_step(&cursor) > 0) {
293                 ip = sp = off = 0;
294                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
295                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
296
297                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
298                 if (ret != 0 && ret != -UNW_ENOMEM) {
299                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
300                 }
301                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
302                         nbuf, (long long)off, (long long)ip,
303                         (long long)sp);
304         }
305
306         (*count)++;
307
308 cleanup:
309         if (aspace) {
310                 unw_destroy_addr_space(aspace);
311         }
312
313         if (pinfo) {
314                 _UPT_destroy(pinfo);
315         }
316
317         ptrace(PTRACE_DETACH, pid, NULL, NULL);
318 }
319
320 static int stack_trace_server(pid_t pid, void *priv)
321 {
322         print_stack_trace(pid, (int *)priv);
323         return 0;
324 }
325
326 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
327                                   struct messaging_context *msg_ctx,
328                                   const struct server_id pid,
329                                   const int argc, const char **argv)
330 {
331         pid_t   dest;
332         int     count = 0;
333
334         if (argc != 1) {
335                 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
336                 return False;
337         }
338
339         dest = procid_to_pid(&pid);
340
341         if (dest != 0) {
342                 /* It would be nice to be able to make sure that this PID is
343                  * the PID of a smbd/winbind/nmbd process, not some random PID
344                  * the user liked the look of. It doesn't seem like it's worth
345                  * the effort at the moment, however.
346                  */
347                 print_stack_trace(dest, &count);
348         } else {
349                 messaging_dgm_forall(stack_trace_server, &count);
350         }
351
352         return True;
353 }
354
355 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
356
357 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
358                                   struct messaging_context *msg_ctx,
359                                   const struct server_id pid,
360                                   const int argc, const char **argv)
361 {
362         fprintf(stderr,
363                 "Daemon stack tracing is not supported on this platform\n");
364         return False;
365 }
366
367 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
368
369 /* Inject a fault (fatal signal) into a running smbd */
370
371 static bool do_inject_fault(struct tevent_context *ev_ctx,
372                             struct messaging_context *msg_ctx,
373                             const struct server_id pid,
374                             const int argc, const char **argv)
375 {
376         if (argc != 2) {
377                 fprintf(stderr, "Usage: smbcontrol <dest> inject "
378                         "<bus|hup|term|internal|segv>\n");
379                 return False;
380         }
381
382 #ifndef DEVELOPER
383         fprintf(stderr, "Fault injection is only available in "
384                 "developer builds\n");
385         return False;
386 #else /* DEVELOPER */
387         {
388                 int sig = 0;
389
390                 if (strcmp(argv[1], "bus") == 0) {
391                         sig = SIGBUS;
392                 } else if (strcmp(argv[1], "hup") == 0) {
393                         sig = SIGHUP;
394                 } else if (strcmp(argv[1], "term") == 0) {
395                         sig = SIGTERM;
396                 } else if (strcmp(argv[1], "segv") == 0) {
397                         sig = SIGSEGV;
398                 } else if (strcmp(argv[1], "internal") == 0) {
399                         /* Force an internal error, ie. an unclean exit. */
400                         sig = -1;
401                 } else {
402                         fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
403                         return False;
404                 }
405
406                 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
407                                     &sig, sizeof(int));
408         }
409 #endif /* DEVELOPER */
410 }
411
412 /* Force a browser election */
413
414 static bool do_election(struct tevent_context *ev_ctx,
415                         struct messaging_context *msg_ctx,
416                         const struct server_id pid,
417                         const int argc, const char **argv)
418 {
419         if (argc != 1) {
420                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
421                 return False;
422         }
423
424         return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
425 }
426
427 /* Ping a samba daemon process */
428
429 static void pong_cb(struct messaging_context *msg,
430                     void *private_data, 
431                     uint32_t msg_type, 
432                     struct server_id pid,
433                     DATA_BLOB *data)
434 {
435         struct server_id_buf src_string;
436         printf("PONG from pid %s\n", server_id_str_buf(pid, &src_string));
437         num_replies++;
438 }
439
440 static bool do_ping(struct tevent_context *ev_ctx,
441                     struct messaging_context *msg_ctx,
442                     const struct server_id pid,
443                     const int argc, const char **argv)
444 {
445         if (argc != 1) {
446                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
447                 return False;
448         }
449
450         /* Send a message and register our interest in a reply */
451
452         if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
453                 return False;
454
455         messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
456
457         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
458
459         /* No replies were received within the timeout period */
460
461         if (num_replies == 0)
462                 printf("No replies received\n");
463
464         messaging_deregister(msg_ctx, MSG_PONG, NULL);
465
466         return num_replies;
467 }
468
469 /* Set profiling options */
470
471 static bool do_profile(struct tevent_context *ev_ctx,
472                        struct messaging_context *msg_ctx,
473                        const struct server_id pid,
474                        const int argc, const char **argv)
475 {
476         int v;
477
478         if (argc != 2) {
479                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
480                         "<off|count|on|flush>\n");
481                 return False;
482         }
483
484         if (strcmp(argv[1], "off") == 0) {
485                 v = 0;
486         } else if (strcmp(argv[1], "count") == 0) {
487                 v = 1;
488         } else if (strcmp(argv[1], "on") == 0) {
489                 v = 2;
490         } else if (strcmp(argv[1], "flush") == 0) {
491                 v = 3;
492         } else {
493                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
494                 return False;
495         }
496
497         return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
498 }
499
500 /* Return the profiling level */
501
502 static void profilelevel_cb(struct messaging_context *msg_ctx,
503                             void *private_data, 
504                             uint32_t msg_type, 
505                             struct server_id pid,
506                             DATA_BLOB *data)
507 {
508         int level;
509         const char *s;
510
511         num_replies++;
512
513         if (data->length != sizeof(int)) {
514                 fprintf(stderr, "invalid message length %ld returned\n", 
515                         (unsigned long)data->length);
516                 return;
517         }
518
519         memcpy(&level, data->data, sizeof(int));
520
521         switch (level) {
522         case 0:
523                 s = "not enabled";
524                 break;
525         case 1:
526                 s = "off";
527                 break;
528         case 3:
529                 s = "count only";
530                 break;
531         case 7:
532                 s = "count and time";
533                 break;
534         default:
535                 s = "BOGUS";
536                 break;
537         }
538
539         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
540 }
541
542 static void profilelevel_rqst(struct messaging_context *msg_ctx,
543                               void *private_data, 
544                               uint32_t msg_type, 
545                               struct server_id pid,
546                               DATA_BLOB *data)
547 {
548         int v = 0;
549
550         /* Send back a dummy reply */
551
552         send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
553 }
554
555 static bool do_profilelevel(struct tevent_context *ev_ctx,
556                             struct messaging_context *msg_ctx,
557                             const struct server_id pid,
558                             const int argc, const char **argv)
559 {
560         if (argc != 1) {
561                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
562                 return False;
563         }
564
565         /* Send a message and register our interest in a reply */
566
567         if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
568                 return False;
569
570         messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
571         messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
572                            profilelevel_rqst);
573
574         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
575
576         /* No replies were received within the timeout period */
577
578         if (num_replies == 0)
579                 printf("No replies received\n");
580
581         messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
582
583         return num_replies;
584 }
585
586 /* Display debug level settings */
587
588 static bool do_debuglevel(struct tevent_context *ev_ctx,
589                           struct messaging_context *msg_ctx,
590                           const struct server_id pid,
591                           const int argc, const char **argv)
592 {
593         if (argc != 1) {
594                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
595                 return False;
596         }
597
598         /* Send a message and register our interest in a reply */
599
600         if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
601                 return False;
602
603         messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
604
605         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
606
607         /* No replies were received within the timeout period */
608
609         if (num_replies == 0)
610                 printf("No replies received\n");
611
612         messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
613
614         return num_replies;
615 }
616
617 /* Send a print notify message */
618
619 static bool do_printnotify(struct tevent_context *ev_ctx,
620                            struct messaging_context *msg_ctx,
621                            const struct server_id pid,
622                            const int argc, const char **argv)
623 {
624         const char *cmd;
625
626         /* Check for subcommand */
627
628         if (argc == 1) {
629                 fprintf(stderr, "Must specify subcommand:\n");
630                 fprintf(stderr, "\tqueuepause <printername>\n");
631                 fprintf(stderr, "\tqueueresume <printername>\n");
632                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
633                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
634                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
635                 fprintf(stderr, "\tprinter <printername> <comment|port|"
636                         "driver> <value>\n");
637
638                 return False;
639         }
640
641         cmd = argv[1];
642
643         if (strcmp(cmd, "queuepause") == 0) {
644
645                 if (argc != 3) {
646                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
647                                 " queuepause <printername>\n");
648                         return False;
649                 }
650
651                 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
652                                              PRINTER_STATUS_PAUSED);
653
654                 goto send;
655
656         } else if (strcmp(cmd, "queueresume") == 0) {
657
658                 if (argc != 3) {
659                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
660                                 " queuereume <printername>\n");
661                         return False;
662                 }
663
664                 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
665                                              PRINTER_STATUS_OK);
666
667                 goto send;
668
669         } else if (strcmp(cmd, "jobpause") == 0) {
670                 int jobid;
671
672                 if (argc != 4) {
673                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
674                                 " jobpause <printername> <unix-jobid>\n");
675                         return False;
676                 }
677
678                 jobid = atoi(argv[3]);
679
680                 notify_job_status_byname(
681                         ev_ctx, msg_ctx,
682                         argv[2], jobid, JOB_STATUS_PAUSED,
683                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
684
685                 goto send;
686
687         } else if (strcmp(cmd, "jobresume") == 0) {
688                 int jobid;
689
690                 if (argc != 4) {
691                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
692                                 " jobpause <printername> <unix-jobid>\n");
693                         return False;
694                 }
695
696                 jobid = atoi(argv[3]);
697
698                 notify_job_status_byname(
699                         ev_ctx, msg_ctx,
700                         argv[2], jobid, JOB_STATUS_QUEUED, 
701                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
702
703                 goto send;
704
705         } else if (strcmp(cmd, "jobdelete") == 0) {
706                 int jobid;
707
708                 if (argc != 4) {
709                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
710                                 " jobpause <printername> <unix-jobid>\n");
711                         return False;
712                 }
713
714                 jobid = atoi(argv[3]);
715
716                 notify_job_status_byname(
717                         ev_ctx, msg_ctx,
718                         argv[2], jobid, JOB_STATUS_DELETING,
719                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
720
721                 notify_job_status_byname(
722                         ev_ctx, msg_ctx,
723                         argv[2], jobid, JOB_STATUS_DELETING|
724                         JOB_STATUS_DELETED,
725                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
726
727                 goto send;
728
729         } else if (strcmp(cmd, "printer") == 0) {
730                 uint32_t attribute;
731
732                 if (argc != 5) {
733                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
734                                 "printer <printername> <comment|port|driver> "
735                                 "<value>\n");
736                         return False;
737                 }
738
739                 if (strcmp(argv[3], "comment") == 0) {
740                         attribute = PRINTER_NOTIFY_FIELD_COMMENT;
741                 } else if (strcmp(argv[3], "port") == 0) {
742                         attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
743                 } else if (strcmp(argv[3], "driver") == 0) {
744                         attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
745                 } else {
746                         fprintf(stderr, "Invalid printer command '%s'\n",
747                                 argv[3]);
748                         return False;
749                 }
750
751                 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
752                                       discard_const_p(char, argv[4]));
753
754                 goto send;
755         }
756
757         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
758         return False;
759
760 send:
761         print_notify_send_messages(msg_ctx, 0);
762         return True;
763 }
764
765 /* Close a share */
766
767 static bool do_closeshare(struct tevent_context *ev_ctx,
768                           struct messaging_context *msg_ctx,
769                           const struct server_id pid,
770                           const int argc, const char **argv)
771 {
772         if (argc != 2) {
773                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
774                         "<sharename>\n");
775                 return False;
776         }
777
778         return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
779                             strlen(argv[1]) + 1);
780 }
781
782 /* Kill a client by IP address */
783 static bool do_kill_client_by_ip(struct tevent_context *ev_ctx,
784                                  struct messaging_context *msg_ctx,
785                                  const struct server_id pid,
786                                  const int argc, const char **argv)
787 {
788         if (argc != 2) {
789                 fprintf(stderr, "Usage: smbcontrol <dest> kill-client-ip "
790                         "<IP address>\n");
791                 return false;
792         }
793
794         if (!is_ipaddress_v4(argv[1]) && !is_ipaddress_v6(argv[1])) {
795                 fprintf(stderr, "%s is not a valid IP address!\n", argv[1]);
796                 return false;
797         }
798
799         return send_message(msg_ctx, pid, MSG_SMB_KILL_CLIENT_IP,
800                             argv[1], strlen(argv[1]) + 1);
801 }
802
803 /* Tell winbindd an IP got dropped */
804
805 static bool do_ip_dropped(struct tevent_context *ev_ctx,
806                           struct messaging_context *msg_ctx,
807                           const struct server_id pid,
808                           const int argc, const char **argv)
809 {
810         if (argc != 2) {
811                 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
812                         "<ip-address>\n");
813                 return False;
814         }
815
816         return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
817                             strlen(argv[1]) + 1);
818 }
819
820 /* force a blocking lock retry */
821
822 static bool do_lockretry(struct tevent_context *ev_ctx,
823                          struct messaging_context *msg_ctx,
824                          const struct server_id pid,
825                          const int argc, const char **argv)
826 {
827         if (argc != 1) {
828                 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
829                 return False;
830         }
831
832         return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
833 }
834
835 /* force a validation of all brl entries, including re-sends. */
836
837 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
838                               struct messaging_context *msg_ctx,
839                               const struct server_id pid,
840                               const int argc, const char **argv)
841 {
842         if (argc != 1) {
843                 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
844                 return False;
845         }
846
847         return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
848 }
849
850 /* Display talloc pool usage */
851
852 static bool do_poolusage(struct tevent_context *ev_ctx,
853                          struct messaging_context *msg_ctx,
854                          const struct server_id pid,
855                          const int argc, const char **argv)
856 {
857         if (argc != 1) {
858                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
859                 return False;
860         }
861
862         messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
863
864         /* Send a message and register our interest in a reply */
865
866         if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
867                 return False;
868
869         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
870
871         /* No replies were received within the timeout period */
872
873         if (num_replies == 0)
874                 printf("No replies received\n");
875
876         messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
877
878         return num_replies;
879 }
880
881 /* Fetch and print the ringbuf log */
882
883 static void print_ringbuf_log_cb(struct messaging_context *msg,
884                                  void *private_data,
885                                  uint32_t msg_type,
886                                  struct server_id pid,
887                                  DATA_BLOB *data)
888 {
889         printf("%s", (const char *)data->data);
890         num_replies++;
891 }
892
893 static bool do_ringbuflog(struct tevent_context *ev_ctx,
894                           struct messaging_context *msg_ctx,
895                           const struct server_id pid,
896                           const int argc, const char **argv)
897 {
898         if (argc != 1) {
899                 fprintf(stderr, "Usage: smbcontrol <dest> ringbuf-log\n");
900                 return false;
901         }
902
903         messaging_register(msg_ctx, NULL, MSG_RINGBUF_LOG,
904                            print_ringbuf_log_cb);
905
906         /* Send a message and register our interest in a reply */
907
908         if (!send_message(msg_ctx, pid, MSG_REQ_RINGBUF_LOG, NULL, 0)) {
909                 return false;
910         }
911
912         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
913
914         /* No replies were received within the timeout period */
915
916         if (num_replies == 0) {
917                 printf("No replies received\n");
918         }
919
920         messaging_deregister(msg_ctx, MSG_RINGBUF_LOG, NULL);
921
922         return num_replies != 0;
923 }
924
925 /* Perform a dmalloc mark */
926
927 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
928                             struct messaging_context *msg_ctx,
929                             const struct server_id pid,
930                             const int argc, const char **argv)
931 {
932         if (argc != 1) {
933                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
934                 return False;
935         }
936
937         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
938 }
939
940 /* Perform a dmalloc changed */
941
942 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
943                                struct messaging_context *msg_ctx,
944                                const struct server_id pid,
945                                const int argc, const char **argv)
946 {
947         if (argc != 1) {
948                 fprintf(stderr, "Usage: smbcontrol <dest> "
949                         "dmalloc-log-changed\n");
950                 return False;
951         }
952
953         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
954                             NULL, 0);
955 }
956
957 static void print_uint32_cb(struct messaging_context *msg, void *private_data,
958                             uint32_t msg_type, struct server_id pid,
959                             DATA_BLOB *data)
960 {
961         uint32_t num_children;
962
963         if (data->length != sizeof(uint32_t)) {
964                 printf("Invalid response: %d bytes long\n",
965                        (int)data->length);
966                 goto done;
967         }
968         num_children = IVAL(data->data, 0);
969         printf("%u children\n", (unsigned)num_children);
970 done:
971         num_replies++;
972 }
973
974 static bool do_num_children(struct tevent_context *ev_ctx,
975                             struct messaging_context *msg_ctx,
976                             const struct server_id pid,
977                             const int argc, const char **argv)
978 {
979         if (argc != 1) {
980                 fprintf(stderr, "Usage: smbcontrol <dest> num-children\n");
981                 return False;
982         }
983
984         messaging_register(msg_ctx, NULL, MSG_SMB_NUM_CHILDREN,
985                            print_uint32_cb);
986
987         /* Send a message and register our interest in a reply */
988
989         if (!send_message(msg_ctx, pid, MSG_SMB_TELL_NUM_CHILDREN, NULL, 0))
990                 return false;
991
992         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
993
994         /* No replies were received within the timeout period */
995
996         if (num_replies == 0)
997                 printf("No replies received\n");
998
999         messaging_deregister(msg_ctx, MSG_SMB_NUM_CHILDREN, NULL);
1000
1001         return num_replies;
1002 }
1003
1004 static bool do_msg_cleanup(struct tevent_context *ev_ctx,
1005                            struct messaging_context *msg_ctx,
1006                            const struct server_id pid,
1007                            const int argc, const char **argv)
1008 {
1009         int ret;
1010
1011         ret = messaging_cleanup(msg_ctx, pid.pid);
1012
1013         printf("cleanup(%u) returned %s\n", (unsigned)pid.pid,
1014                ret ? strerror(ret) : "ok");
1015
1016         return (ret == 0);
1017 }
1018
1019 /* Shutdown a server process */
1020
1021 static bool do_shutdown(struct tevent_context *ev_ctx,
1022                         struct messaging_context *msg_ctx,
1023                         const struct server_id pid,
1024                         const int argc, const char **argv)
1025 {
1026         if (argc != 1) {
1027                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
1028                 return False;
1029         }
1030
1031         return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
1032 }
1033
1034 /* Notify a driver upgrade */
1035
1036 static bool do_drvupgrade(struct tevent_context *ev_ctx,
1037                           struct messaging_context *msg_ctx,
1038                           const struct server_id pid,
1039                           const int argc, const char **argv)
1040 {
1041         if (argc != 2) {
1042                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
1043                         "<driver-name>\n");
1044                 return False;
1045         }
1046
1047         return send_message(msg_ctx, pid, MSG_PRINTER_DRVUPGRADE, argv[1],
1048                             strlen(argv[1]) + 1);
1049 }
1050
1051 static bool do_winbind_online(struct tevent_context *ev_ctx,
1052                               struct messaging_context *msg_ctx,
1053                               const struct server_id pid,
1054                               const int argc, const char **argv)
1055 {
1056         TDB_CONTEXT *tdb;
1057         char *db_path;
1058
1059         if (argc != 1) {
1060                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
1061                 return False;
1062         }
1063
1064         db_path = state_path("winbindd_cache.tdb");
1065         if (db_path == NULL) {
1066                 return false;
1067         }
1068
1069         /* Remove the entry in the winbindd_cache tdb to tell a later
1070            starting winbindd that we're online. */
1071
1072         tdb = tdb_open_log(db_path, 0, TDB_DEFAULT, O_RDWR, 0600);
1073         if (!tdb) {
1074                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1075                         db_path);
1076                 TALLOC_FREE(db_path);
1077                 return False;
1078         }
1079
1080         TALLOC_FREE(db_path);
1081         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
1082         tdb_close(tdb);
1083
1084         return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
1085 }
1086
1087 static bool do_winbind_offline(struct tevent_context *ev_ctx,
1088                                struct messaging_context *msg_ctx,
1089                                const struct server_id pid,
1090                                const int argc, const char **argv)
1091 {
1092         TDB_CONTEXT *tdb;
1093         bool ret = False;
1094         int retry = 0;
1095         char *db_path;
1096
1097         if (argc != 1) {
1098                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
1099                 return False;
1100         }
1101
1102         db_path = state_path("winbindd_cache.tdb");
1103         if (db_path == NULL) {
1104                 return false;
1105         }
1106
1107         /* Create an entry in the winbindd_cache tdb to tell a later
1108            starting winbindd that we're offline. We may actually create
1109            it here... */
1110
1111         tdb = tdb_open_log(db_path,
1112                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
1113                                 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
1114                                 O_RDWR|O_CREAT, 0600);
1115
1116         if (!tdb) {
1117                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1118                         db_path);
1119                 TALLOC_FREE(db_path);
1120                 return False;
1121         }
1122         TALLOC_FREE(db_path);
1123
1124         /* There's a potential race condition that if a child
1125            winbindd detects a domain is online at the same time
1126            we're trying to tell it to go offline that it might 
1127            delete the record we add between us adding it and
1128            sending the message. Minimize this by retrying up to
1129            5 times. */
1130
1131         for (retry = 0; retry < 5; retry++) {
1132                 uint8_t buf[4];
1133                 TDB_DATA d = { .dptr = buf, .dsize = sizeof(buf) };
1134
1135                 SIVAL(buf, 0, time(NULL));
1136
1137                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1138
1139                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1140                                    NULL, 0);
1141
1142                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1143                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1144
1145                 if (!d.dptr || d.dsize != 4) {
1146                         SAFE_FREE(d.dptr);
1147                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1148                 } else {
1149                         SAFE_FREE(d.dptr);
1150                         break;
1151                 }
1152         }
1153
1154         tdb_close(tdb);
1155         return ret;
1156 }
1157
1158 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1159                                     struct messaging_context *msg_ctx,
1160                                     const struct server_id pid,
1161                                     const int argc, const char **argv)
1162 {
1163         if (argc != 1) {
1164                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1165                 return False;
1166         }
1167
1168         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1169                            print_pid_string_cb);
1170
1171         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, NULL, 0)) {
1172                 return False;
1173         }
1174
1175         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1176
1177         /* No replies were received within the timeout period */
1178
1179         if (num_replies == 0)
1180                 printf("No replies received\n");
1181
1182         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1183
1184         return num_replies;
1185 }
1186
1187 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1188                                         struct messaging_context *msg_ctx,
1189                                         const struct server_id pid,
1190                                         const int argc, const char **argv)
1191 {
1192         const char *domain = NULL;
1193         int domain_len = 0;
1194
1195         if (argc < 1 || argc > 2) {
1196                 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1197                         "<domain>\n");
1198                 return false;
1199         }
1200
1201         if (argc == 2) {
1202                 domain = argv[1];
1203                 domain_len = strlen(argv[1]) + 1;
1204         }
1205
1206         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1207                            print_pid_string_cb);
1208
1209         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1210                           domain, domain_len))
1211         {
1212                 return false;
1213         }
1214
1215         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1216
1217         /* No replies were received within the timeout period */
1218
1219         if (num_replies == 0) {
1220                 printf("No replies received\n");
1221         }
1222
1223         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1224
1225         return num_replies;
1226 }
1227
1228 static bool do_msg_disconnect_dc(struct tevent_context *ev_ctx,
1229                                  struct messaging_context *msg_ctx,
1230                                  const struct server_id pid,
1231                                  const int argc, const char **argv)
1232 {
1233         if (argc != 1) {
1234                 fprintf(stderr, "Usage: smbcontrol <dest> disconnect-dc\n");
1235                 return False;
1236         }
1237
1238         return send_message(msg_ctx, pid, MSG_WINBIND_DISCONNECT_DC, NULL, 0);
1239 }
1240
1241 static void winbind_validate_cache_cb(struct messaging_context *msg,
1242                                       void *private_data,
1243                                       uint32_t msg_type,
1244                                       struct server_id pid,
1245                                       DATA_BLOB *data)
1246 {
1247         struct server_id_buf src_string;
1248         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1249                (*(data->data) == 0 ? "" : "NOT "),
1250                server_id_str_buf(pid, &src_string));
1251         num_replies++;
1252 }
1253
1254 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1255                                       struct messaging_context *msg_ctx,
1256                                       const struct server_id pid,
1257                                       const int argc, const char **argv)
1258 {
1259         struct server_id myid;
1260
1261         myid = messaging_server_id(msg_ctx);
1262
1263         if (argc != 1) {
1264                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1265                 return False;
1266         }
1267
1268         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1269                            winbind_validate_cache_cb);
1270
1271         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1272                           sizeof(myid))) {
1273                 return False;
1274         }
1275
1276         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1277
1278         if (num_replies == 0) {
1279                 printf("No replies received\n");
1280         }
1281
1282         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1283
1284         return num_replies;
1285 }
1286
1287 static bool do_reload_config(struct tevent_context *ev_ctx,
1288                              struct messaging_context *msg_ctx,
1289                              const struct server_id pid,
1290                              const int argc, const char **argv)
1291 {
1292         if (argc != 1) {
1293                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1294                 return False;
1295         }
1296
1297         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1298 }
1299
1300 static bool do_reload_printers(struct tevent_context *ev_ctx,
1301                                struct messaging_context *msg_ctx,
1302                                const struct server_id pid,
1303                                const int argc, const char **argv)
1304 {
1305         if (argc != 1) {
1306                 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1307                 return False;
1308         }
1309
1310         return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1311 }
1312
1313 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1314 {
1315         fstring unix_name;
1316         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1317         fstrcpy(unix_name, name);
1318         (void)strupper_m(unix_name);
1319         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1320         n->name_type = (unsigned int)type & 0xFF;
1321         push_ascii(n->scope,  lp_netbios_scope(), 64, STR_TERMINATE);
1322 }
1323
1324 static bool do_nodestatus(struct tevent_context *ev_ctx,
1325                           struct messaging_context *msg_ctx,
1326                           const struct server_id pid,
1327                           const int argc, const char **argv)
1328 {
1329         struct packet_struct p;
1330
1331         if (argc != 2) {
1332                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1333                 return False;
1334         }
1335
1336         ZERO_STRUCT(p);
1337
1338         p.ip = interpret_addr2(argv[1]);
1339         p.port = 137;
1340         p.packet_type = NMB_PACKET;
1341
1342         p.packet.nmb.header.name_trn_id = 10;
1343         p.packet.nmb.header.opcode = 0;
1344         p.packet.nmb.header.response = False;
1345         p.packet.nmb.header.nm_flags.bcast = False;
1346         p.packet.nmb.header.nm_flags.recursion_available = False;
1347         p.packet.nmb.header.nm_flags.recursion_desired = False;
1348         p.packet.nmb.header.nm_flags.trunc = False;
1349         p.packet.nmb.header.nm_flags.authoritative = False;
1350         p.packet.nmb.header.rcode = 0;
1351         p.packet.nmb.header.qdcount = 1;
1352         p.packet.nmb.header.ancount = 0;
1353         p.packet.nmb.header.nscount = 0;
1354         p.packet.nmb.header.arcount = 0;
1355         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1356         p.packet.nmb.question.question_type = 0x21;
1357         p.packet.nmb.question.question_class = 0x1;
1358
1359         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1360 }
1361
1362 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1363                               struct messaging_context *msg_ctx,
1364                               const struct server_id pid,
1365                               const int argc, const char **argv)
1366 {
1367         if (argc != 1) {
1368                 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1369                 return false;
1370         }
1371         return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1372 }
1373
1374 /* A list of message type supported */
1375
1376 static const struct {
1377         const char *name;       /* Option name */
1378         bool (*fn)(struct tevent_context *ev_ctx,
1379                    struct messaging_context *msg_ctx,
1380                    const struct server_id pid,
1381                    const int argc, const char **argv);
1382         const char *help;       /* Short help text */
1383 } msg_types[] = {
1384         { "debug", do_debug, "Set debuglevel"  },
1385         { "idmap", do_idmap, "Manipulate idmap cache" },
1386         { "force-election", do_election,
1387           "Force a browse election" },
1388         { "ping", do_ping, "Elicit a response" },
1389         { "profile", do_profile, "" },
1390         { "inject", do_inject_fault,
1391             "Inject a fatal signal into a running smbd"},
1392         { "stacktrace", do_daemon_stack_trace,
1393             "Display a stack trace of a daemon" },
1394         { "profilelevel", do_profilelevel, "" },
1395         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1396         { "printnotify", do_printnotify, "Send a print notify message" },
1397         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1398         { "kill-client-ip", do_kill_client_by_ip,
1399           "Forcibly disconnect a client with a specific IP address" },
1400         { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1401         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1402         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1403         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1404         { "ringbuf-log", do_ringbuflog, "Display ringbuf log" },
1405         { "dmalloc-mark", do_dmalloc_mark, "" },
1406         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1407         { "shutdown", do_shutdown, "Shut down daemon" },
1408         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1409         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1410         { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1411         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1412         { "online", do_winbind_online, "Ask winbind to go into online state"},
1413         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1414         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1415         { "validate-cache" , do_winbind_validate_cache,
1416           "Validate winbind's credential cache" },
1417         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1418         { "disconnect-dc", do_msg_disconnect_dc },
1419         { "notify-cleanup", do_notify_cleanup },
1420         { "num-children", do_num_children,
1421           "Print number of smbd child processes" },
1422         { "msg-cleanup", do_msg_cleanup },
1423         { "noop", do_noop, "Do nothing" },
1424         { NULL }
1425 };
1426
1427 /* Display usage information */
1428
1429 static void usage(poptContext pc)
1430 {
1431         int i;
1432
1433         poptPrintHelp(pc, stderr, 0);
1434
1435         fprintf(stderr, "\n");
1436         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1437                 "process ID\n");
1438
1439         fprintf(stderr, "\n");
1440         fprintf(stderr, "<message-type> is one of:\n");
1441
1442         for (i = 0; msg_types[i].name; i++) 
1443             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1444                     msg_types[i].help);
1445
1446         fprintf(stderr, "\n");
1447
1448         exit(1);
1449 }
1450
1451 /* Return the pid number for a string destination */
1452
1453 static struct server_id parse_dest(struct messaging_context *msg,
1454                                    const char *dest)
1455 {
1456         struct server_id result = {-1};
1457         pid_t pid;
1458
1459         /* Zero is a special return value for broadcast to all processes */
1460
1461         if (strequal(dest, "all")) {
1462                 return interpret_pid(MSG_BROADCAST_PID_STR);
1463         }
1464
1465         /* Try self - useful for testing */
1466
1467         if (strequal(dest, "self")) {
1468                 return messaging_server_id(msg);
1469         }
1470
1471         /* Fix winbind typo. */
1472         if (strequal(dest, "winbind")) {
1473                 dest = "winbindd";
1474         }
1475
1476         /* Check for numeric pid number */
1477         result = interpret_pid(dest);
1478
1479         /* Zero isn't valid if not "all". */
1480         if (result.pid && procid_valid(&result)) {
1481                 return result;
1482         }
1483
1484         /* Look up other destinations in pidfile directory */
1485
1486         if ((pid = pidfile_pid(lp_pid_directory(), dest)) != 0) {
1487                 return pid_to_procid(pid);
1488         }
1489
1490         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1491
1492         return result;
1493 }
1494
1495 /* Execute smbcontrol command */
1496
1497 static bool do_command(struct tevent_context *ev_ctx,
1498                        struct messaging_context *msg_ctx,
1499                        int argc, const char **argv)
1500 {
1501         const char *dest = argv[0], *command = argv[1];
1502         struct server_id pid;
1503         int i;
1504
1505         /* Check destination */
1506
1507         pid = parse_dest(msg_ctx, dest);
1508         if (!procid_valid(&pid)) {
1509                 return False;
1510         }
1511
1512         /* Check command */
1513
1514         for (i = 0; msg_types[i].name; i++) {
1515                 if (strequal(command, msg_types[i].name))
1516                         return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1517                                                argc - 1, argv + 1);
1518         }
1519
1520         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1521
1522         return False;
1523 }
1524
1525 static void smbcontrol_help(poptContext pc,
1526                     enum poptCallbackReason preason,
1527                     struct poptOption * poption,
1528                     const char * parg,
1529                     void * pdata)
1530 {
1531         if (poption->shortName != '?') {
1532                 poptPrintUsage(pc, stdout, 0);
1533         } else {
1534                 usage(pc);
1535         }
1536
1537         exit(0);
1538 }
1539
1540 struct poptOption help_options[] = {
1541         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1542           NULL, NULL },
1543         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1544         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1545         { NULL }
1546 } ;
1547
1548 /* Main program */
1549
1550 int main(int argc, const char **argv)
1551 {
1552         poptContext pc;
1553         int opt;
1554         struct tevent_context *evt_ctx;
1555         struct messaging_context *msg_ctx;
1556
1557         static struct poptOption long_options[] = {
1558                 /* POPT_AUTOHELP */
1559                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1560                                         0, "Help options:", NULL },
1561                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1562                   "Set timeout value in seconds", "TIMEOUT" },
1563
1564                 POPT_COMMON_SAMBA
1565                 POPT_TABLEEND
1566         };
1567         TALLOC_CTX *frame = talloc_stackframe();
1568         int ret = 0;
1569
1570         smb_init_locale();
1571
1572         setup_logging(argv[0], DEBUG_STDOUT);
1573         lp_set_cmdline("log level", "0");
1574
1575         /* Parse command line arguments using popt */
1576
1577         pc = poptGetContext(
1578                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1579
1580         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1581                                "<parameters>");
1582
1583         if (argc == 1)
1584                 usage(pc);
1585
1586         while ((opt = poptGetNextOpt(pc)) != -1) {
1587                 switch(opt) {
1588                 case 't':       /* --timeout */
1589                         break;
1590                 default:
1591                         fprintf(stderr, "Invalid option\n");
1592                         poptPrintHelp(pc, stderr, 0);
1593                         break;
1594                 }
1595         }
1596
1597         /* We should now have the remaining command line arguments in
1598            argv.  The argc parameter should have been decremented to the
1599            correct value in the above switch statement. */
1600
1601         argv = (const char **)poptGetArgs(pc);
1602         argc = 0;
1603         if (argv != NULL) {
1604                 while (argv[argc] != NULL) {
1605                         argc++;
1606                 }
1607         }
1608
1609         if (argc <= 1)
1610                 usage(pc);
1611
1612         lp_load_global(get_dyn_CONFIGFILE());
1613
1614         /* Need to invert sense of return code -- samba
1615          * routines mostly return True==1 for success, but
1616          * shell needs 0. */ 
1617
1618         if (!(evt_ctx = samba_tevent_context_init(NULL)) ||
1619             !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1620                 fprintf(stderr, "could not init messaging context\n");
1621                 TALLOC_FREE(frame);
1622                 exit(1);
1623         }
1624
1625         ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1626         TALLOC_FREE(msg_ctx);
1627         TALLOC_FREE(frame);
1628         return ret;
1629 }