s3-utils: Cleanup code in wait_replies().
[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         te = tevent_add_timer(ev_ctx, NULL,
97                               timeval_current_ofs(timeout, 0),
98                               smbcontrol_timeout, (void *)&timed_out);
99         if (te == NULL) {
100                 DEBUG(0, ("tevent_add_timer failed\n"));
101                 return;
102         }
103
104         while (!timed_out) {
105                 int ret;
106                 if (num_replies > 0 && !multiple_replies)
107                         break;
108                 ret = tevent_loop_once(ev_ctx);
109                 if (ret != 0) {
110                         break;
111                 }
112         }
113 }
114
115 /* Message handler callback that displays the PID and a string on stdout */
116
117 static void print_pid_string_cb(struct messaging_context *msg,
118                                 void *private_data, 
119                                 uint32_t msg_type, 
120                                 struct server_id pid,
121                                 DATA_BLOB *data)
122 {
123         char *pidstr;
124
125         pidstr = server_id_str(talloc_tos(), &pid);
126         printf("PID %s: %.*s", pidstr, (int)data->length,
127                (const char *)data->data);
128         TALLOC_FREE(pidstr);
129         num_replies++;
130 }
131
132 /* Message handler callback that displays a string on stdout */
133
134 static void print_string_cb(struct messaging_context *msg,
135                             void *private_data, 
136                             uint32_t msg_type, 
137                             struct server_id pid,
138                             DATA_BLOB *data)
139 {
140         printf("%*s", (int)data->length, (const char *)data->data);
141         num_replies++;
142 }
143
144 /* Send no message.  Useful for testing. */
145
146 static bool do_noop(struct tevent_context *ev_ctx,
147                     struct messaging_context *msg_ctx,
148                     const struct server_id pid,
149                     const int argc, const char **argv)
150 {
151         if (argc != 1) {
152                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
153                 return False;
154         }
155
156         /* Move along, nothing to see here */
157
158         return True;
159 }
160
161 /* Send a debug string */
162
163 static bool do_debug(struct tevent_context *ev_ctx,
164                      struct messaging_context *msg_ctx,
165                      const struct server_id pid,
166                      const int argc, const char **argv)
167 {
168         if (argc != 2) {
169                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
170                         "<debug-string>\n");
171                 return False;
172         }
173
174         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
175                             strlen(argv[1]) + 1);
176 }
177
178
179 static bool do_idmap(struct tevent_context *ev,
180                      struct messaging_context *msg_ctx,
181                      const struct server_id pid,
182                      const int argc, const char **argv)
183 {
184         static const char* usage = "Usage: "
185                 "smbcontrol <dest> idmap <cmd> [arg]\n"
186                 "\tcmd:"
187                 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
188                 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
189         const char* arg = NULL;
190         int arglen = 0;
191         int msg_type;
192
193         switch (argc) {
194         case 2:
195                 break;
196         case 3:
197                 arg = argv[2];
198                 arglen = strlen(arg) + 1;
199                 break;
200         default:
201                 fprintf(stderr, "%s", usage);
202                 return false;
203         }
204
205         if (strcmp(argv[1], "delete") == 0) {
206                 msg_type = ID_CACHE_DELETE;
207         }
208         else if (strcmp(argv[1], "kill") == 0) {
209                 msg_type = ID_CACHE_KILL;
210         }
211         else if (strcmp(argv[1], "help") == 0) {
212                 fprintf(stdout, "%s", usage);
213                 return true;
214         }
215         else {
216                 fprintf(stderr, "%s", usage);
217                 return false;
218         }
219
220         return send_message(msg_ctx, pid, msg_type, arg, arglen);
221 }
222
223
224 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
225
226 /* Return the name of a process given it's PID. This will only work on Linux,
227  * but that's probably moot since this whole stack tracing implementatino is
228  * Linux-specific anyway.
229  */
230 static const char * procname(pid_t pid, char * buf, size_t bufsz)
231 {
232         char path[64];
233         FILE * fp;
234
235         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
236                 (unsigned long long)pid);
237         if ((fp = fopen(path, "r")) == NULL) {
238                 return NULL;
239         }
240
241         fgets(buf, bufsz, fp);
242
243         fclose(fp);
244         return buf;
245 }
246
247 static void print_stack_trace(pid_t pid, int * count)
248 {
249         void *              pinfo = NULL;
250         unw_addr_space_t    aspace = NULL;
251         unw_cursor_t        cursor;
252         unw_word_t          ip, sp;
253
254         char                nbuf[256];
255         unw_word_t          off;
256
257         int ret;
258
259         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
260                 fprintf(stderr,
261                         "Failed to attach to process %llu: %s\n",
262                         (unsigned long long)pid, strerror(errno));
263                 return;
264         }
265
266         /* Wait until the attach is complete. */
267         waitpid(pid, NULL, 0);
268
269         if (((pinfo = _UPT_create(pid)) == NULL) ||
270             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
271                 /* Probably out of memory. */
272                 fprintf(stderr,
273                         "Unable to initialize stack unwind for process %llu\n",
274                         (unsigned long long)pid);
275                 goto cleanup;
276         }
277
278         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
279                 fprintf(stderr,
280                         "Unable to unwind stack for process %llu: %s\n",
281                         (unsigned long long)pid, unw_strerror(ret));
282                 goto cleanup;
283         }
284
285         if (*count > 0) {
286                 printf("\n");
287         }
288
289         if (procname(pid, nbuf, sizeof(nbuf))) {
290                 printf("Stack trace for process %llu (%s):\n",
291                         (unsigned long long)pid, nbuf);
292         } else {
293                 printf("Stack trace for process %llu:\n",
294                         (unsigned long long)pid);
295         }
296
297         while (unw_step(&cursor) > 0) {
298                 ip = sp = off = 0;
299                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
300                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
301
302                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
303                 if (ret != 0 && ret != -UNW_ENOMEM) {
304                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
305                 }
306                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
307                         nbuf, (long long)off, (long long)ip,
308                         (long long)sp);
309         }
310
311         (*count)++;
312
313 cleanup:
314         if (aspace) {
315                 unw_destroy_addr_space(aspace);
316         }
317
318         if (pinfo) {
319                 _UPT_destroy(pinfo);
320         }
321
322         ptrace(PTRACE_DETACH, pid, NULL, NULL);
323 }
324
325 static int stack_trace_server(const struct server_id *id,
326                               uint32_t msg_flags,
327                               void *priv)
328 {
329         if (id->vnn == get_my_vnn()) {
330                 print_stack_trace(procid_to_pid(&id->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                 serverid_traverse_read(stack_trace_server, &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         if (argc != 1) {
1068                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1069                 return False;
1070         }
1071
1072         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1073 }
1074
1075 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1076                                         struct messaging_context *msg_ctx,
1077                                         const struct server_id pid,
1078                                         const int argc, const char **argv)
1079 {
1080         const char *domain = NULL;
1081         int domain_len = 0;
1082         struct server_id myid;
1083         uint8_t *buf = NULL;
1084         int buf_len = 0;
1085
1086         myid = messaging_server_id(msg_ctx);
1087
1088         if (argc < 1 || argc > 2) {
1089                 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1090                         "<domain>\n");
1091                 return false;
1092         }
1093
1094         if (argc == 2) {
1095                 domain = argv[1];
1096                 domain_len = strlen(argv[1]) + 1;
1097         }
1098
1099         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1100                            print_pid_string_cb);
1101
1102         buf_len = sizeof(myid)+domain_len;
1103         buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1104         if (!buf) {
1105                 return false;
1106         }
1107
1108         memcpy(buf, &myid, sizeof(myid));
1109         memcpy(&buf[sizeof(myid)], domain, domain_len);
1110
1111         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1112                           buf, buf_len))
1113         {
1114                 SAFE_FREE(buf);
1115                 return false;
1116         }
1117
1118         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1119
1120         /* No replies were received within the timeout period */
1121
1122         SAFE_FREE(buf);
1123         if (num_replies == 0) {
1124                 printf("No replies received\n");
1125         }
1126
1127         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1128
1129         return num_replies;
1130 }
1131
1132 static void winbind_validate_cache_cb(struct messaging_context *msg,
1133                                       void *private_data,
1134                                       uint32_t msg_type,
1135                                       struct server_id pid,
1136                                       DATA_BLOB *data)
1137 {
1138         char *src_string = server_id_str(NULL, &pid);
1139         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1140                (*(data->data) == 0 ? "" : "NOT "), src_string);
1141         TALLOC_FREE(src_string);
1142         num_replies++;
1143 }
1144
1145 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1146                                       struct messaging_context *msg_ctx,
1147                                       const struct server_id pid,
1148                                       const int argc, const char **argv)
1149 {
1150         struct server_id myid;
1151
1152         myid = messaging_server_id(msg_ctx);
1153
1154         if (argc != 1) {
1155                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1156                 return False;
1157         }
1158
1159         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1160                            winbind_validate_cache_cb);
1161
1162         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1163                           sizeof(myid))) {
1164                 return False;
1165         }
1166
1167         wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1168
1169         if (num_replies == 0) {
1170                 printf("No replies received\n");
1171         }
1172
1173         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1174
1175         return num_replies;
1176 }
1177
1178 static bool do_reload_config(struct tevent_context *ev_ctx,
1179                              struct messaging_context *msg_ctx,
1180                              const struct server_id pid,
1181                              const int argc, const char **argv)
1182 {
1183         if (argc != 1) {
1184                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1185                 return False;
1186         }
1187
1188         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1189 }
1190
1191 static bool do_reload_printers(struct tevent_context *ev_ctx,
1192                                struct messaging_context *msg_ctx,
1193                                const struct server_id pid,
1194                                const int argc, const char **argv)
1195 {
1196         if (argc != 1) {
1197                 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1198                 return False;
1199         }
1200
1201         return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1202 }
1203
1204 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1205 {
1206         fstring unix_name;
1207         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1208         fstrcpy(unix_name, name);
1209         (void)strupper_m(unix_name);
1210         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1211         n->name_type = (unsigned int)type & 0xFF;
1212         push_ascii(n->scope,  lp_netbios_scope(), 64, STR_TERMINATE);
1213 }
1214
1215 static bool do_nodestatus(struct tevent_context *ev_ctx,
1216                           struct messaging_context *msg_ctx,
1217                           const struct server_id pid,
1218                           const int argc, const char **argv)
1219 {
1220         struct packet_struct p;
1221
1222         if (argc != 2) {
1223                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1224                 return False;
1225         }
1226
1227         ZERO_STRUCT(p);
1228
1229         p.ip = interpret_addr2(argv[1]);
1230         p.port = 137;
1231         p.packet_type = NMB_PACKET;
1232
1233         p.packet.nmb.header.name_trn_id = 10;
1234         p.packet.nmb.header.opcode = 0;
1235         p.packet.nmb.header.response = False;
1236         p.packet.nmb.header.nm_flags.bcast = False;
1237         p.packet.nmb.header.nm_flags.recursion_available = False;
1238         p.packet.nmb.header.nm_flags.recursion_desired = False;
1239         p.packet.nmb.header.nm_flags.trunc = False;
1240         p.packet.nmb.header.nm_flags.authoritative = False;
1241         p.packet.nmb.header.rcode = 0;
1242         p.packet.nmb.header.qdcount = 1;
1243         p.packet.nmb.header.ancount = 0;
1244         p.packet.nmb.header.nscount = 0;
1245         p.packet.nmb.header.arcount = 0;
1246         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1247         p.packet.nmb.question.question_type = 0x21;
1248         p.packet.nmb.question.question_class = 0x1;
1249
1250         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1251 }
1252
1253 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1254                               struct messaging_context *msg_ctx,
1255                               const struct server_id pid,
1256                               const int argc, const char **argv)
1257 {
1258         if (argc != 1) {
1259                 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1260                 return false;
1261         }
1262         return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1263 }
1264
1265 /* A list of message type supported */
1266
1267 static const struct {
1268         const char *name;       /* Option name */
1269         bool (*fn)(struct tevent_context *ev_ctx,
1270                    struct messaging_context *msg_ctx,
1271                    const struct server_id pid,
1272                    const int argc, const char **argv);
1273         const char *help;       /* Short help text */
1274 } msg_types[] = {
1275         { "debug", do_debug, "Set debuglevel"  },
1276         { "idmap", do_idmap, "Manipulate idmap cache" },
1277         { "force-election", do_election,
1278           "Force a browse election" },
1279         { "ping", do_ping, "Elicit a response" },
1280         { "profile", do_profile, "" },
1281         { "inject", do_inject_fault,
1282             "Inject a fatal signal into a running smbd"},
1283         { "stacktrace", do_daemon_stack_trace,
1284             "Display a stack trace of a daemon" },
1285         { "profilelevel", do_profilelevel, "" },
1286         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1287         { "printnotify", do_printnotify, "Send a print notify message" },
1288         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1289         { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1290         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1291         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1292         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1293         { "dmalloc-mark", do_dmalloc_mark, "" },
1294         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1295         { "shutdown", do_shutdown, "Shut down daemon" },
1296         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1297         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1298         { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1299         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1300         { "online", do_winbind_online, "Ask winbind to go into online state"},
1301         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1302         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1303         { "dump-event-list", do_dump_event_list, "Dump event list"},
1304         { "validate-cache" , do_winbind_validate_cache,
1305           "Validate winbind's credential cache" },
1306         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1307         { "notify-cleanup", do_notify_cleanup },
1308         { "noop", do_noop, "Do nothing" },
1309         { NULL }
1310 };
1311
1312 /* Display usage information */
1313
1314 static void usage(poptContext pc)
1315 {
1316         int i;
1317
1318         poptPrintHelp(pc, stderr, 0);
1319
1320         fprintf(stderr, "\n");
1321         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1322                 "process ID\n");
1323
1324         fprintf(stderr, "\n");
1325         fprintf(stderr, "<message-type> is one of:\n");
1326
1327         for (i = 0; msg_types[i].name; i++) 
1328             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1329                     msg_types[i].help);
1330
1331         fprintf(stderr, "\n");
1332
1333         exit(1);
1334 }
1335
1336 /* Return the pid number for a string destination */
1337
1338 static struct server_id parse_dest(struct messaging_context *msg,
1339                                    const char *dest)
1340 {
1341         struct server_id result = {-1};
1342         pid_t pid;
1343
1344         /* Zero is a special return value for broadcast to all processes */
1345
1346         if (strequal(dest, "all")) {
1347                 return interpret_pid(MSG_BROADCAST_PID_STR);
1348         }
1349
1350         /* Try self - useful for testing */
1351
1352         if (strequal(dest, "self")) {
1353                 return messaging_server_id(msg);
1354         }
1355
1356         /* Fix winbind typo. */
1357         if (strequal(dest, "winbind")) {
1358                 dest = "winbindd";
1359         }
1360
1361         /* Check for numeric pid number */
1362         result = interpret_pid(dest);
1363
1364         /* Zero isn't valid if not "all". */
1365         if (result.pid && procid_valid(&result)) {
1366                 return result;
1367         }
1368
1369         /* Look up other destinations in pidfile directory */
1370
1371         if ((pid = pidfile_pid(lp_piddir(), dest)) != 0) {
1372                 return pid_to_procid(pid);
1373         }
1374
1375         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1376
1377         return result;
1378 }
1379
1380 /* Execute smbcontrol command */
1381
1382 static bool do_command(struct tevent_context *ev_ctx,
1383                        struct messaging_context *msg_ctx,
1384                        int argc, const char **argv)
1385 {
1386         const char *dest = argv[0], *command = argv[1];
1387         struct server_id pid;
1388         int i;
1389
1390         /* Check destination */
1391
1392         pid = parse_dest(msg_ctx, dest);
1393         if (!procid_valid(&pid)) {
1394                 return False;
1395         }
1396
1397         /* Check command */
1398
1399         for (i = 0; msg_types[i].name; i++) {
1400                 if (strequal(command, msg_types[i].name))
1401                         return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1402                                                argc - 1, argv + 1);
1403         }
1404
1405         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1406
1407         return False;
1408 }
1409
1410 static void smbcontrol_help(poptContext pc,
1411                     enum poptCallbackReason preason,
1412                     struct poptOption * poption,
1413                     const char * parg,
1414                     void * pdata)
1415 {
1416         if (poption->shortName != '?') {
1417                 poptPrintUsage(pc, stdout, 0);
1418         } else {
1419                 usage(pc);
1420         }
1421
1422         exit(0);
1423 }
1424
1425 struct poptOption help_options[] = {
1426         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1427           NULL, NULL },
1428         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1429         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1430         { NULL }
1431 } ;
1432
1433 /* Main program */
1434
1435 int main(int argc, const char **argv)
1436 {
1437         poptContext pc;
1438         int opt;
1439         struct tevent_context *evt_ctx;
1440         struct messaging_context *msg_ctx;
1441
1442         static struct poptOption long_options[] = {
1443                 /* POPT_AUTOHELP */
1444                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1445                                         0, "Help options:", NULL },
1446                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1447                   "Set timeout value in seconds", "TIMEOUT" },
1448
1449                 POPT_COMMON_SAMBA
1450                 POPT_TABLEEND
1451         };
1452         TALLOC_CTX *frame = talloc_stackframe();
1453         int ret = 0;
1454
1455         load_case_tables();
1456
1457         setup_logging(argv[0], DEBUG_STDOUT);
1458
1459         /* Parse command line arguments using popt */
1460
1461         pc = poptGetContext(
1462                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1463
1464         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1465                                "<parameters>");
1466
1467         if (argc == 1)
1468                 usage(pc);
1469
1470         while ((opt = poptGetNextOpt(pc)) != -1) {
1471                 switch(opt) {
1472                 case 't':       /* --timeout */
1473                         break;
1474                 default:
1475                         fprintf(stderr, "Invalid option\n");
1476                         poptPrintHelp(pc, stderr, 0);
1477                         break;
1478                 }
1479         }
1480
1481         /* We should now have the remaining command line arguments in
1482            argv.  The argc parameter should have been decremented to the
1483            correct value in the above switch statement. */
1484
1485         argv = (const char **)poptGetArgs(pc);
1486         argc = 0;
1487         if (argv != NULL) {
1488                 while (argv[argc] != NULL) {
1489                         argc++;
1490                 }
1491         }
1492
1493         if (argc <= 1)
1494                 usage(pc);
1495
1496         lp_load_global(get_dyn_CONFIGFILE());
1497
1498         /* Need to invert sense of return code -- samba
1499          * routines mostly return True==1 for success, but
1500          * shell needs 0. */ 
1501
1502         if (!(evt_ctx = tevent_context_init(NULL)) ||
1503             !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1504                 fprintf(stderr, "could not init messaging context\n");
1505                 TALLOC_FREE(frame);
1506                 exit(1);
1507         }
1508
1509         ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1510         TALLOC_FREE(frame);
1511         return ret;
1512 }