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