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