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