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