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