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