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