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