SQ
[obnox/samba/samba-obnox.git] / source3 / utils / smbcontrol.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Send messages to other Samba daemons
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 1994-1998
8    Copyright (C) Martin Pool 2001-2002
9    Copyright (C) Simo Sorce 2002
10    Copyright (C) James Peach 2006
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 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 *)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 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                 TDB_DATA d;
1097                 uint8 buf[4];
1098
1099                 ZERO_STRUCT(d);
1100
1101                 SIVAL(buf, 0, time(NULL));
1102                 d.dptr = buf;
1103                 d.dsize = 4;
1104
1105                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1106
1107                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1108                                    NULL, 0);
1109
1110                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1111                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1112
1113                 if (!d.dptr || d.dsize != 4) {
1114                         SAFE_FREE(d.dptr);
1115                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1116                 } else {
1117                         SAFE_FREE(d.dptr);
1118                         break;
1119                 }
1120         }
1121
1122         tdb_close(tdb);
1123         return ret;
1124 }
1125
1126 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1127                                     struct messaging_context *msg_ctx,
1128                                     const struct server_id pid,
1129                                     const int argc, const char **argv)
1130 {
1131         struct server_id myid;
1132
1133         myid = messaging_server_id(msg_ctx);
1134
1135         if (argc != 1) {
1136                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1137                 return False;
1138         }
1139
1140         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1141                            print_pid_string_cb);
1142
1143         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1144                           sizeof(myid)))
1145                 return False;
1146
1147         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1148
1149         /* No replies were received within the timeout period */
1150
1151         if (num_replies == 0)
1152                 printf("No replies received\n");
1153
1154         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1155
1156         return num_replies;
1157 }
1158
1159 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1160                                struct messaging_context *msg_ctx,
1161                                const struct server_id pid,
1162                                const int argc, const char **argv)
1163 {
1164         if (argc != 1) {
1165                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1166                 return False;
1167         }
1168
1169         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1170 }
1171
1172 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1173                                         struct messaging_context *msg_ctx,
1174                                         const struct server_id pid,
1175                                         const int argc, const char **argv)
1176 {
1177         const char *domain = NULL;
1178         int domain_len = 0;
1179         struct server_id myid;
1180         uint8_t *buf = NULL;
1181         int buf_len = 0;
1182
1183         myid = messaging_server_id(msg_ctx);
1184
1185         if (argc < 1 || argc > 2) {
1186                 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1187                         "<domain>\n");
1188                 return false;
1189         }
1190
1191         if (argc == 2) {
1192                 domain = argv[1];
1193                 domain_len = strlen(argv[1]) + 1;
1194         }
1195
1196         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1197                            print_pid_string_cb);
1198
1199         buf_len = sizeof(myid)+domain_len;
1200         buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1201         if (!buf) {
1202                 return false;
1203         }
1204
1205         memcpy(buf, &myid, sizeof(myid));
1206         memcpy(&buf[sizeof(myid)], domain, domain_len);
1207
1208         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1209                           buf, buf_len))
1210         {
1211                 SAFE_FREE(buf);
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         SAFE_FREE(buf);
1220         if (num_replies == 0) {
1221                 printf("No replies received\n");
1222         }
1223
1224         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1225
1226         return num_replies;
1227 }
1228
1229 static void winbind_validate_cache_cb(struct messaging_context *msg,
1230                                       void *private_data,
1231                                       uint32_t msg_type,
1232                                       struct server_id pid,
1233                                       DATA_BLOB *data)
1234 {
1235         struct server_id_buf src_string;
1236         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1237                (*(data->data) == 0 ? "" : "NOT "),
1238                server_id_str_buf(pid, &src_string));
1239         num_replies++;
1240 }
1241
1242 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1243                                       struct messaging_context *msg_ctx,
1244                                       const struct server_id pid,
1245                                       const int argc, const char **argv)
1246 {
1247         struct server_id myid;
1248
1249         myid = messaging_server_id(msg_ctx);
1250
1251         if (argc != 1) {
1252                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1253                 return False;
1254         }
1255
1256         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1257                            winbind_validate_cache_cb);
1258
1259         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1260                           sizeof(myid))) {
1261                 return False;
1262         }
1263
1264         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1265
1266         if (num_replies == 0) {
1267                 printf("No replies received\n");
1268         }
1269
1270         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1271
1272         return num_replies;
1273 }
1274
1275 static bool do_reload_config(struct tevent_context *ev_ctx,
1276                              struct messaging_context *msg_ctx,
1277                              const struct server_id pid,
1278                              const int argc, const char **argv)
1279 {
1280         if (argc != 1) {
1281                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1282                 return False;
1283         }
1284
1285         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1286 }
1287
1288 static bool do_reload_printers(struct tevent_context *ev_ctx,
1289                                struct messaging_context *msg_ctx,
1290                                const struct server_id pid,
1291                                const int argc, const char **argv)
1292 {
1293         if (argc != 1) {
1294                 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1295                 return False;
1296         }
1297
1298         return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1299 }
1300
1301 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1302 {
1303         fstring unix_name;
1304         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1305         fstrcpy(unix_name, name);
1306         (void)strupper_m(unix_name);
1307         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1308         n->name_type = (unsigned int)type & 0xFF;
1309         push_ascii(n->scope,  lp_netbios_scope(), 64, STR_TERMINATE);
1310 }
1311
1312 static bool do_nodestatus(struct tevent_context *ev_ctx,
1313                           struct messaging_context *msg_ctx,
1314                           const struct server_id pid,
1315                           const int argc, const char **argv)
1316 {
1317         struct packet_struct p;
1318
1319         if (argc != 2) {
1320                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1321                 return False;
1322         }
1323
1324         ZERO_STRUCT(p);
1325
1326         p.ip = interpret_addr2(argv[1]);
1327         p.port = 137;
1328         p.packet_type = NMB_PACKET;
1329
1330         p.packet.nmb.header.name_trn_id = 10;
1331         p.packet.nmb.header.opcode = 0;
1332         p.packet.nmb.header.response = False;
1333         p.packet.nmb.header.nm_flags.bcast = False;
1334         p.packet.nmb.header.nm_flags.recursion_available = False;
1335         p.packet.nmb.header.nm_flags.recursion_desired = False;
1336         p.packet.nmb.header.nm_flags.trunc = False;
1337         p.packet.nmb.header.nm_flags.authoritative = False;
1338         p.packet.nmb.header.rcode = 0;
1339         p.packet.nmb.header.qdcount = 1;
1340         p.packet.nmb.header.ancount = 0;
1341         p.packet.nmb.header.nscount = 0;
1342         p.packet.nmb.header.arcount = 0;
1343         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1344         p.packet.nmb.question.question_type = 0x21;
1345         p.packet.nmb.question.question_class = 0x1;
1346
1347         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1348 }
1349
1350 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1351                               struct messaging_context *msg_ctx,
1352                               const struct server_id pid,
1353                               const int argc, const char **argv)
1354 {
1355         if (argc != 1) {
1356                 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1357                 return false;
1358         }
1359         return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1360 }
1361
1362 /* A list of message type supported */
1363
1364 static const struct {
1365         const char *name;       /* Option name */
1366         bool (*fn)(struct tevent_context *ev_ctx,
1367                    struct messaging_context *msg_ctx,
1368                    const struct server_id pid,
1369                    const int argc, const char **argv);
1370         const char *help;       /* Short help text */
1371 } msg_types[] = {
1372         { "debug", do_debug, "Set debuglevel"  },
1373         { "idmap", do_idmap, "Manipulate idmap cache" },
1374         { "force-election", do_election,
1375           "Force a browse election" },
1376         { "ping", do_ping, "Elicit a response" },
1377         { "profile", do_profile, "" },
1378         { "inject", do_inject_fault,
1379             "Inject a fatal signal into a running smbd"},
1380         { "stacktrace", do_daemon_stack_trace,
1381             "Display a stack trace of a daemon" },
1382         { "profilelevel", do_profilelevel, "" },
1383         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1384         { "printnotify", do_printnotify, "Send a print notify message" },
1385         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1386         { "kill-client-ip", do_kill_client_by_ip,
1387           "Forcibly disconnect a client with a specific IP address" },
1388         { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1389         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1390         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1391         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1392         { "dmalloc-mark", do_dmalloc_mark, "" },
1393         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1394         { "shutdown", do_shutdown, "Shut down daemon" },
1395         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1396         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1397         { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1398         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1399         { "online", do_winbind_online, "Ask winbind to go into online state"},
1400         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1401         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1402         { "dump-event-list", do_dump_event_list, "Dump event list"},
1403         { "validate-cache" , do_winbind_validate_cache,
1404           "Validate winbind's credential cache" },
1405         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1406         { "notify-cleanup", do_notify_cleanup },
1407         { "num-children", do_num_children,
1408           "Print number of smbd child processes" },
1409         { "msg-cleanup", do_msg_cleanup },
1410         { "noop", do_noop, "Do nothing" },
1411         { NULL }
1412 };
1413
1414 /* Display usage information */
1415
1416 static void usage(poptContext pc)
1417 {
1418         int i;
1419
1420         poptPrintHelp(pc, stderr, 0);
1421
1422         fprintf(stderr, "\n");
1423         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1424                 "process ID\n");
1425
1426         fprintf(stderr, "\n");
1427         fprintf(stderr, "<message-type> is one of:\n");
1428
1429         for (i = 0; msg_types[i].name; i++) 
1430             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1431                     msg_types[i].help);
1432
1433         fprintf(stderr, "\n");
1434
1435         exit(1);
1436 }
1437
1438 /* Return the pid number for a string destination */
1439
1440 static struct server_id parse_dest(struct messaging_context *msg,
1441                                    const char *dest)
1442 {
1443         struct server_id result = {-1};
1444         pid_t pid;
1445
1446         /* Zero is a special return value for broadcast to all processes */
1447
1448         if (strequal(dest, "all")) {
1449                 return interpret_pid(MSG_BROADCAST_PID_STR);
1450         }
1451
1452         /* Try self - useful for testing */
1453
1454         if (strequal(dest, "self")) {
1455                 return messaging_server_id(msg);
1456         }
1457
1458         /* Fix winbind typo. */
1459         if (strequal(dest, "winbind")) {
1460                 dest = "winbindd";
1461         }
1462
1463         /* Check for numeric pid number */
1464         result = interpret_pid(dest);
1465
1466         /* Zero isn't valid if not "all". */
1467         if (result.pid && procid_valid(&result)) {
1468                 return result;
1469         }
1470
1471         /* Look up other destinations in pidfile directory */
1472
1473         if ((pid = pidfile_pid(lp_pid_directory(), dest)) != 0) {
1474                 return pid_to_procid(pid);
1475         }
1476
1477         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1478
1479         return result;
1480 }
1481
1482 /* Execute smbcontrol command */
1483
1484 static bool do_command(struct tevent_context *ev_ctx,
1485                        struct messaging_context *msg_ctx,
1486                        int argc, const char **argv)
1487 {
1488         const char *dest = argv[0], *command = argv[1];
1489         struct server_id pid;
1490         int i;
1491
1492         /* Check destination */
1493
1494         pid = parse_dest(msg_ctx, dest);
1495         if (!procid_valid(&pid)) {
1496                 return False;
1497         }
1498
1499         /* Check command */
1500
1501         for (i = 0; msg_types[i].name; i++) {
1502                 if (strequal(command, msg_types[i].name))
1503                         return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1504                                                argc - 1, argv + 1);
1505         }
1506
1507         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1508
1509         return False;
1510 }
1511
1512 static void smbcontrol_help(poptContext pc,
1513                     enum poptCallbackReason preason,
1514                     struct poptOption * poption,
1515                     const char * parg,
1516                     void * pdata)
1517 {
1518         if (poption->shortName != '?') {
1519                 poptPrintUsage(pc, stdout, 0);
1520         } else {
1521                 usage(pc);
1522         }
1523
1524         exit(0);
1525 }
1526
1527 struct poptOption help_options[] = {
1528         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1529           NULL, NULL },
1530         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1531         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1532         { NULL }
1533 } ;
1534
1535 /* Main program */
1536
1537 int main(int argc, const char **argv)
1538 {
1539         poptContext pc;
1540         int opt;
1541         struct tevent_context *evt_ctx;
1542         struct messaging_context *msg_ctx;
1543
1544         static struct poptOption long_options[] = {
1545                 /* POPT_AUTOHELP */
1546                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1547                                         0, "Help options:", NULL },
1548                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1549                   "Set timeout value in seconds", "TIMEOUT" },
1550
1551                 POPT_COMMON_SAMBA
1552                 POPT_TABLEEND
1553         };
1554         TALLOC_CTX *frame = talloc_stackframe();
1555         int ret = 0;
1556
1557         load_case_tables();
1558
1559         setup_logging(argv[0], DEBUG_STDOUT);
1560
1561         /* Parse command line arguments using popt */
1562
1563         pc = poptGetContext(
1564                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1565
1566         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1567                                "<parameters>");
1568
1569         if (argc == 1)
1570                 usage(pc);
1571
1572         while ((opt = poptGetNextOpt(pc)) != -1) {
1573                 switch(opt) {
1574                 case 't':       /* --timeout */
1575                         break;
1576                 default:
1577                         fprintf(stderr, "Invalid option\n");
1578                         poptPrintHelp(pc, stderr, 0);
1579                         break;
1580                 }
1581         }
1582
1583         /* We should now have the remaining command line arguments in
1584            argv.  The argc parameter should have been decremented to the
1585            correct value in the above switch statement. */
1586
1587         argv = (const char **)poptGetArgs(pc);
1588         argc = 0;
1589         if (argv != NULL) {
1590                 while (argv[argc] != NULL) {
1591                         argc++;
1592                 }
1593         }
1594
1595         if (argc <= 1)
1596                 usage(pc);
1597
1598         lp_load_global(get_dyn_CONFIGFILE());
1599
1600         /* Need to invert sense of return code -- samba
1601          * routines mostly return True==1 for success, but
1602          * shell needs 0. */ 
1603
1604         if (!(evt_ctx = samba_tevent_context_init(NULL)) ||
1605             !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1606                 fprintf(stderr, "could not init messaging context\n");
1607                 TALLOC_FREE(frame);
1608                 exit(1);
1609         }
1610
1611         ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1612         TALLOC_FREE(msg_ctx);
1613         TALLOC_FREE(frame);
1614         return ret;
1615 }