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