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