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