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