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