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