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