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