83ccce7057f7d6e9c63b232c5cba54de107a1ef5
[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 static BOOL do_dump_event_list(struct messaging_context *msg_ctx,
986                                const struct server_id pid,
987                                const int argc, const char **argv)
988 {
989         struct server_id myid;
990
991         myid = pid_to_procid(sys_getpid());
992
993         if (argc != 1) {
994                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
995                 return False;
996         }
997
998         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
999 }
1000
1001
1002 static BOOL do_reload_config(struct messaging_context *msg_ctx,
1003                              const struct server_id pid,
1004                              const int argc, const char **argv)
1005 {
1006         if (argc != 1) {
1007                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1008                 return False;
1009         }
1010
1011         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1012 }
1013
1014 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1015 {
1016         fstring unix_name;
1017         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1018         fstrcpy(unix_name, name);
1019         strupper_m(unix_name);
1020         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1021         n->name_type = (unsigned int)type & 0xFF;
1022         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
1023 }
1024
1025 static BOOL do_nodestatus(struct messaging_context *msg_ctx,
1026                           const struct server_id pid,
1027                           const int argc, const char **argv)
1028 {
1029         struct packet_struct p;
1030
1031         if (argc != 2) {
1032                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1033                 return False;
1034         }
1035
1036         ZERO_STRUCT(p);
1037
1038         p.ip = *interpret_addr2(argv[1]);
1039         p.port = 137;
1040         p.packet_type = NMB_PACKET;
1041
1042         p.packet.nmb.header.name_trn_id = 10;
1043         p.packet.nmb.header.opcode = 0;
1044         p.packet.nmb.header.response = False;
1045         p.packet.nmb.header.nm_flags.bcast = False;
1046         p.packet.nmb.header.nm_flags.recursion_available = False;
1047         p.packet.nmb.header.nm_flags.recursion_desired = False;
1048         p.packet.nmb.header.nm_flags.trunc = False;
1049         p.packet.nmb.header.nm_flags.authoritative = False;
1050         p.packet.nmb.header.rcode = 0;
1051         p.packet.nmb.header.qdcount = 1;
1052         p.packet.nmb.header.ancount = 0;
1053         p.packet.nmb.header.nscount = 0;
1054         p.packet.nmb.header.arcount = 0;
1055         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1056         p.packet.nmb.question.question_type = 0x21;
1057         p.packet.nmb.question.question_class = 0x1;
1058
1059         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1060 }
1061
1062 /* A list of message type supported */
1063
1064 static const struct {
1065         const char *name;       /* Option name */
1066         BOOL (*fn)(struct messaging_context *msg_ctx,
1067                    const struct server_id pid,
1068                    const int argc, const char **argv);
1069         const char *help;       /* Short help text */
1070 } msg_types[] = {
1071         { "debug", do_debug, "Set debuglevel"  },
1072         { "force-election", do_election,
1073           "Force a browse election" },
1074         { "ping", do_ping, "Elicit a response" },
1075         { "profile", do_profile, "" },
1076         { "inject", do_inject_fault,
1077             "Inject a fatal signal into a running smbd"},
1078         { "stacktrace", do_daemon_stack_trace,
1079             "Display a stack trace of a daemon" },
1080         { "profilelevel", do_profilelevel, "" },
1081         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1082         { "printnotify", do_printnotify, "Send a print notify message" },
1083         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1084         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1085         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1086         { "samsync", do_samsync, "Initiate SAM synchronisation" },
1087         { "samrepl", do_samrepl, "Initiate SAM replication" },
1088         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1089         { "dmalloc-mark", do_dmalloc_mark, "" },
1090         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1091         { "shutdown", do_shutdown, "Shut down daemon" },
1092         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1093         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1094         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1095         { "online", do_winbind_online, "Ask winbind to go into online state"},
1096         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1097         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1098         { "dump-event-list", do_dump_event_list, "Dump event list"},
1099         { "noop", do_noop, "Do nothing" },
1100         { NULL }
1101 };
1102
1103 /* Display usage information */
1104
1105 static void usage(poptContext pc)
1106 {
1107         int i;
1108
1109         poptPrintHelp(pc, stderr, 0);
1110
1111         fprintf(stderr, "\n");
1112         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1113                 "process ID\n");
1114
1115         fprintf(stderr, "\n");
1116         fprintf(stderr, "<message-type> is one of:\n");
1117
1118         for (i = 0; msg_types[i].name; i++) 
1119             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1120                     msg_types[i].help);
1121
1122         fprintf(stderr, "\n");
1123
1124         exit(1);
1125 }
1126
1127 /* Return the pid number for a string destination */
1128
1129 static struct server_id parse_dest(const char *dest)
1130 {
1131         struct server_id result = {-1};
1132         pid_t pid;
1133
1134         /* Zero is a special return value for broadcast smbd */
1135
1136         if (strequal(dest, "smbd")) {
1137                 return interpret_pid("0");
1138         }
1139
1140         /* Try self - useful for testing */
1141
1142         if (strequal(dest, "self")) {
1143                 return pid_to_procid(sys_getpid());
1144         }
1145
1146         /* Fix winbind typo. */
1147         if (strequal(dest, "winbind")) {
1148                 dest = "winbindd";
1149         }
1150
1151         
1152         if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1153                 /* Check for numeric pid number */
1154
1155                 result = interpret_pid(dest);
1156
1157                 /* Zero isn't valid if not smbd. */
1158                 if (result.pid && procid_valid(&result)) {
1159                         return result;
1160                 }
1161         }
1162
1163         /* Look up other destinations in pidfile directory */
1164
1165         if ((pid = pidfile_pid(dest)) != 0) {
1166                 return pid_to_procid(pid);
1167         }
1168
1169         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1170
1171         return result;
1172 }       
1173
1174 /* Execute smbcontrol command */
1175
1176 static BOOL do_command(struct messaging_context *msg_ctx,
1177                        int argc, const char **argv)
1178 {
1179         const char *dest = argv[0], *command = argv[1];
1180         struct server_id pid;
1181         int i;
1182
1183         /* Check destination */
1184
1185         pid = parse_dest(dest);
1186         if (!procid_valid(&pid)) {
1187                 return False;
1188         }
1189
1190         /* Check command */
1191
1192         for (i = 0; msg_types[i].name; i++) {
1193                 if (strequal(command, msg_types[i].name))
1194                         return msg_types[i].fn(msg_ctx, pid,
1195                                                argc - 1, argv + 1);
1196         }
1197
1198         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1199
1200         return False;
1201 }
1202
1203 static void smbcontrol_help(poptContext pc,
1204                     enum poptCallbackReason preason,
1205                     struct poptOption * poption,
1206                     const char * parg,
1207                     void * pdata)
1208 {
1209         if (poption->shortName != '?') {
1210                 poptPrintUsage(pc, stdout, 0);
1211         } else {
1212                 usage(pc);
1213         }
1214
1215         exit(0);
1216 }
1217
1218 struct poptOption help_options[] = {
1219         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1220           NULL, NULL },
1221         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1222         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1223         { NULL }
1224 } ;
1225
1226 /* Main program */
1227
1228 int main(int argc, const char **argv)
1229 {
1230         poptContext pc;
1231         int opt;
1232         struct event_context *evt_ctx;
1233         struct messaging_context *msg_ctx;
1234
1235         static struct poptOption long_options[] = {
1236                 /* POPT_AUTOHELP */
1237                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1238                                         0, "Help options:", NULL },
1239                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1240                   "Set timeout value in seconds", "TIMEOUT" },
1241
1242                 POPT_COMMON_SAMBA
1243                 POPT_TABLEEND
1244         };
1245
1246         load_case_tables();
1247
1248         setup_logging(argv[0],True);
1249         
1250         /* Parse command line arguments using popt */
1251
1252         pc = poptGetContext(
1253                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1254
1255         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1256                                "<parameters>");
1257
1258         if (argc == 1)
1259                 usage(pc);
1260
1261         while ((opt = poptGetNextOpt(pc)) != -1) {
1262                 switch(opt) {
1263                 case 't':       /* --timeout */
1264                         break;
1265                 default:
1266                         fprintf(stderr, "Invalid option\n");
1267                         poptPrintHelp(pc, stderr, 0);
1268                         break;
1269                 }
1270         }
1271
1272         /* We should now have the remaining command line arguments in
1273            argv.  The argc parameter should have been decremented to the
1274            correct value in the above switch statement. */
1275
1276         argv = (const char **)poptGetArgs(pc);
1277         argc = 0;
1278         while (argv[argc] != NULL) {
1279                 argc++;
1280         }
1281
1282         if (argc == 1)
1283                 usage(pc);
1284
1285         lp_load(dyn_CONFIGFILE,False,False,False,True);
1286
1287         /* Need to invert sense of return code -- samba
1288          * routines mostly return True==1 for success, but
1289          * shell needs 0. */ 
1290         
1291         if (!(evt_ctx = event_context_init(NULL)) ||
1292             !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1293                 fprintf(stderr, "could not init messaging context\n");
1294                 exit(1);
1295         }
1296         
1297         return !do_command(msg_ctx, argc, argv);
1298 }