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