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