release-scripts: add build-htmlman-nogit
[Samba/bb.git] / source3 / utils / smbcontrol.c
blobf4daf830885a958e85533c3868754a5e9912b127
1 /*
2 Unix SMB/CIFS implementation.
4 Send messages to other Samba daemons
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
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.
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.
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/>.
26 #include "includes.h"
27 #include "popt_common.h"
28 #include "librpc/gen_ndr/messaging.h"
29 #include "librpc/gen_ndr/spoolss.h"
30 #include "nt_printing.h"
32 #if HAVE_LIBUNWIND_H
33 #include <libunwind.h>
34 #endif
36 #if HAVE_LIBUNWIND_PTRACE_H
37 #include <libunwind-ptrace.h>
38 #endif
40 #if HAVE_SYS_PTRACE_H
41 #include <sys/ptrace.h>
42 #endif
44 /* Default timeout value when waiting for replies (in seconds) */
46 #define DEFAULT_TIMEOUT 10
48 static int timeout = DEFAULT_TIMEOUT;
49 static int num_replies; /* Used by message callback fns */
51 /* Send a message to a destination pid. Zero means broadcast smbd. */
53 static bool send_message(struct messaging_context *msg_ctx,
54 struct server_id pid, int msg_type,
55 const void *buf, int len)
57 bool ret;
58 int n_sent = 0;
60 if (procid_to_pid(&pid) != 0)
61 return NT_STATUS_IS_OK(
62 messaging_send_buf(msg_ctx, pid, msg_type,
63 (uint8 *)buf, len));
65 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
66 DEBUG(10,("smbcontrol/send_message: broadcast message to "
67 "%d processes\n", n_sent));
69 return ret;
72 static void smbcontrol_timeout(struct tevent_context *event_ctx,
73 struct tevent_timer *te,
74 struct timeval now,
75 void *private_data)
77 bool *timed_out = (bool *)private_data;
78 TALLOC_FREE(te);
79 *timed_out = True;
82 /* Wait for one or more reply messages */
84 static void wait_replies(struct messaging_context *msg_ctx,
85 bool multiple_replies)
87 struct tevent_timer *te;
88 bool timed_out = False;
90 if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
91 timeval_current_ofs(timeout, 0),
92 smbcontrol_timeout, (void *)&timed_out))) {
93 DEBUG(0, ("tevent_add_timer failed\n"));
94 return;
97 while (!timed_out) {
98 int ret;
99 if (num_replies > 0 && !multiple_replies)
100 break;
101 ret = tevent_loop_once(messaging_event_context(msg_ctx));
102 if (ret != 0) {
103 break;
108 /* Message handler callback that displays the PID and a string on stdout */
110 static void print_pid_string_cb(struct messaging_context *msg,
111 void *private_data,
112 uint32_t msg_type,
113 struct server_id pid,
114 DATA_BLOB *data)
116 char *pidstr;
118 pidstr = procid_str(talloc_tos(), &pid);
119 printf("PID %s: %.*s", pidstr, (int)data->length,
120 (const char *)data->data);
121 TALLOC_FREE(pidstr);
122 num_replies++;
125 /* Message handler callback that displays a string on stdout */
127 static void print_string_cb(struct messaging_context *msg,
128 void *private_data,
129 uint32_t msg_type,
130 struct server_id pid,
131 DATA_BLOB *data)
133 printf("%*s", (int)data->length, (const char *)data->data);
134 num_replies++;
137 /* Send no message. Useful for testing. */
139 static bool do_noop(struct messaging_context *msg_ctx,
140 const struct server_id pid,
141 const int argc, const char **argv)
143 if (argc != 1) {
144 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
145 return False;
148 /* Move along, nothing to see here */
150 return True;
153 /* Send a debug string */
155 static bool do_debug(struct messaging_context *msg_ctx,
156 const struct server_id pid,
157 const int argc, const char **argv)
159 if (argc != 2) {
160 fprintf(stderr, "Usage: smbcontrol <dest> debug "
161 "<debug-string>\n");
162 return False;
165 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
166 strlen(argv[1]) + 1);
169 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
171 /* Return the name of a process given it's PID. This will only work on Linux,
172 * but that's probably moot since this whole stack tracing implementatino is
173 * Linux-specific anyway.
175 static const char * procname(pid_t pid, char * buf, size_t bufsz)
177 char path[64];
178 FILE * fp;
180 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
181 (unsigned long long)pid);
182 if ((fp = fopen(path, "r")) == NULL) {
183 return NULL;
186 fgets(buf, bufsz, fp);
188 fclose(fp);
189 return buf;
192 static void print_stack_trace(pid_t pid, int * count)
194 void * pinfo = NULL;
195 unw_addr_space_t aspace = NULL;
196 unw_cursor_t cursor;
197 unw_word_t ip, sp;
199 char nbuf[256];
200 unw_word_t off;
202 int ret;
204 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
205 fprintf(stderr,
206 "Failed to attach to process %llu: %s\n",
207 (unsigned long long)pid, strerror(errno));
208 return;
211 /* Wait until the attach is complete. */
212 waitpid(pid, NULL, 0);
214 if (((pinfo = _UPT_create(pid)) == NULL) ||
215 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
216 /* Probably out of memory. */
217 fprintf(stderr,
218 "Unable to initialize stack unwind for process %llu\n",
219 (unsigned long long)pid);
220 goto cleanup;
223 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
224 fprintf(stderr,
225 "Unable to unwind stack for process %llu: %s\n",
226 (unsigned long long)pid, unw_strerror(ret));
227 goto cleanup;
230 if (*count > 0) {
231 printf("\n");
234 if (procname(pid, nbuf, sizeof(nbuf))) {
235 printf("Stack trace for process %llu (%s):\n",
236 (unsigned long long)pid, nbuf);
237 } else {
238 printf("Stack trace for process %llu:\n",
239 (unsigned long long)pid);
242 while (unw_step(&cursor) > 0) {
243 ip = sp = off = 0;
244 unw_get_reg(&cursor, UNW_REG_IP, &ip);
245 unw_get_reg(&cursor, UNW_REG_SP, &sp);
247 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
248 if (ret != 0 && ret != -UNW_ENOMEM) {
249 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
251 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
252 nbuf, (long long)off, (long long)ip,
253 (long long)sp);
256 (*count)++;
258 cleanup:
259 if (aspace) {
260 unw_destroy_addr_space(aspace);
263 if (pinfo) {
264 _UPT_destroy(pinfo);
267 ptrace(PTRACE_DETACH, pid, NULL, NULL);
270 static int stack_trace_connection(const struct connections_key *key,
271 const struct connections_data *crec,
272 void *priv)
274 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
276 return 0;
279 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
280 const struct server_id pid,
281 const int argc, const char **argv)
283 pid_t dest;
284 int count = 0;
286 if (argc != 1) {
287 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
288 return False;
291 dest = procid_to_pid(&pid);
293 if (dest != 0) {
294 /* It would be nice to be able to make sure that this PID is
295 * the PID of a smbd/winbind/nmbd process, not some random PID
296 * the user liked the look of. It doesn't seem like it's worth
297 * the effort at the moment, however.
299 print_stack_trace(dest, &count);
300 } else {
301 connections_forall_read(stack_trace_connection, &count);
304 return True;
307 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
309 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
310 const struct server_id pid,
311 const int argc, const char **argv)
313 fprintf(stderr,
314 "Daemon stack tracing is not supported on this platform\n");
315 return False;
318 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
320 /* Inject a fault (fatal signal) into a running smbd */
322 static bool do_inject_fault(struct messaging_context *msg_ctx,
323 const struct server_id pid,
324 const int argc, const char **argv)
326 if (argc != 2) {
327 fprintf(stderr, "Usage: smbcontrol <dest> inject "
328 "<bus|hup|term|internal|segv>\n");
329 return False;
332 #ifndef DEVELOPER
333 fprintf(stderr, "Fault injection is only available in "
334 "developer builds\n");
335 return False;
336 #else /* DEVELOPER */
338 int sig = 0;
340 if (strcmp(argv[1], "bus") == 0) {
341 sig = SIGBUS;
342 } else if (strcmp(argv[1], "hup") == 0) {
343 sig = SIGHUP;
344 } else if (strcmp(argv[1], "term") == 0) {
345 sig = SIGTERM;
346 } else if (strcmp(argv[1], "segv") == 0) {
347 sig = SIGSEGV;
348 } else if (strcmp(argv[1], "internal") == 0) {
349 /* Force an internal error, ie. an unclean exit. */
350 sig = -1;
351 } else {
352 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
353 return False;
356 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
357 &sig, sizeof(int));
359 #endif /* DEVELOPER */
362 /* Force a browser election */
364 static bool do_election(struct messaging_context *msg_ctx,
365 const struct server_id pid,
366 const int argc, const char **argv)
368 if (argc != 1) {
369 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
370 return False;
373 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
376 /* Ping a samba daemon process */
378 static void pong_cb(struct messaging_context *msg,
379 void *private_data,
380 uint32_t msg_type,
381 struct server_id pid,
382 DATA_BLOB *data)
384 char *src_string = procid_str(NULL, &pid);
385 printf("PONG from pid %s\n", src_string);
386 TALLOC_FREE(src_string);
387 num_replies++;
390 static bool do_ping(struct messaging_context *msg_ctx,
391 const struct server_id pid,
392 const int argc, const char **argv)
394 if (argc != 1) {
395 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
396 return False;
399 /* Send a message and register our interest in a reply */
401 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
402 return False;
404 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
406 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
408 /* No replies were received within the timeout period */
410 if (num_replies == 0)
411 printf("No replies received\n");
413 messaging_deregister(msg_ctx, MSG_PONG, NULL);
415 return num_replies;
418 /* Set profiling options */
420 static bool do_profile(struct messaging_context *msg_ctx,
421 const struct server_id pid,
422 const int argc, const char **argv)
424 int v;
426 if (argc != 2) {
427 fprintf(stderr, "Usage: smbcontrol <dest> profile "
428 "<off|count|on|flush>\n");
429 return False;
432 if (strcmp(argv[1], "off") == 0) {
433 v = 0;
434 } else if (strcmp(argv[1], "count") == 0) {
435 v = 1;
436 } else if (strcmp(argv[1], "on") == 0) {
437 v = 2;
438 } else if (strcmp(argv[1], "flush") == 0) {
439 v = 3;
440 } else {
441 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
442 return False;
445 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
448 /* Return the profiling level */
450 static void profilelevel_cb(struct messaging_context *msg_ctx,
451 void *private_data,
452 uint32_t msg_type,
453 struct server_id pid,
454 DATA_BLOB *data)
456 int level;
457 const char *s;
459 num_replies++;
461 if (data->length != sizeof(int)) {
462 fprintf(stderr, "invalid message length %ld returned\n",
463 (unsigned long)data->length);
464 return;
467 memcpy(&level, data->data, sizeof(int));
469 switch (level) {
470 case 0:
471 s = "not enabled";
472 break;
473 case 1:
474 s = "off";
475 break;
476 case 3:
477 s = "count only";
478 break;
479 case 7:
480 s = "count and time";
481 break;
482 default:
483 s = "BOGUS";
484 break;
487 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
490 static void profilelevel_rqst(struct messaging_context *msg_ctx,
491 void *private_data,
492 uint32_t msg_type,
493 struct server_id pid,
494 DATA_BLOB *data)
496 int v = 0;
498 /* Send back a dummy reply */
500 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
503 static bool do_profilelevel(struct messaging_context *msg_ctx,
504 const struct server_id pid,
505 const int argc, const char **argv)
507 if (argc != 1) {
508 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
509 return False;
512 /* Send a message and register our interest in a reply */
514 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
515 return False;
517 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
518 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
519 profilelevel_rqst);
521 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
523 /* No replies were received within the timeout period */
525 if (num_replies == 0)
526 printf("No replies received\n");
528 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
530 return num_replies;
533 /* Display debug level settings */
535 static bool do_debuglevel(struct messaging_context *msg_ctx,
536 const struct server_id pid,
537 const int argc, const char **argv)
539 if (argc != 1) {
540 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
541 return False;
544 /* Send a message and register our interest in a reply */
546 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
547 return False;
549 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
551 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
553 /* No replies were received within the timeout period */
555 if (num_replies == 0)
556 printf("No replies received\n");
558 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
560 return num_replies;
563 /* Send a print notify message */
565 static bool do_printnotify(struct messaging_context *msg_ctx,
566 const struct server_id pid,
567 const int argc, const char **argv)
569 const char *cmd;
571 /* Check for subcommand */
573 if (argc == 1) {
574 fprintf(stderr, "Must specify subcommand:\n");
575 fprintf(stderr, "\tqueuepause <printername>\n");
576 fprintf(stderr, "\tqueueresume <printername>\n");
577 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
578 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
579 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
580 fprintf(stderr, "\tprinter <printername> <comment|port|"
581 "driver> <value>\n");
583 return False;
586 cmd = argv[1];
588 if (strcmp(cmd, "queuepause") == 0) {
590 if (argc != 3) {
591 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
592 " queuepause <printername>\n");
593 return False;
596 notify_printer_status_byname(messaging_event_context(msg_ctx),
597 msg_ctx, argv[2],
598 PRINTER_STATUS_PAUSED);
600 goto send;
602 } else if (strcmp(cmd, "queueresume") == 0) {
604 if (argc != 3) {
605 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
606 " queuereume <printername>\n");
607 return False;
610 notify_printer_status_byname(messaging_event_context(msg_ctx),
611 msg_ctx, argv[2],
612 PRINTER_STATUS_OK);
614 goto send;
616 } else if (strcmp(cmd, "jobpause") == 0) {
617 int jobid;
619 if (argc != 4) {
620 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
621 " jobpause <printername> <unix-jobid>\n");
622 return False;
625 jobid = atoi(argv[3]);
627 notify_job_status_byname(
628 messaging_event_context(msg_ctx), msg_ctx,
629 argv[2], jobid, JOB_STATUS_PAUSED,
630 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
632 goto send;
634 } else if (strcmp(cmd, "jobresume") == 0) {
635 int jobid;
637 if (argc != 4) {
638 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
639 " jobpause <printername> <unix-jobid>\n");
640 return False;
643 jobid = atoi(argv[3]);
645 notify_job_status_byname(
646 messaging_event_context(msg_ctx), msg_ctx,
647 argv[2], jobid, JOB_STATUS_QUEUED,
648 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
650 goto send;
652 } else if (strcmp(cmd, "jobdelete") == 0) {
653 int jobid;
655 if (argc != 4) {
656 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
657 " jobpause <printername> <unix-jobid>\n");
658 return False;
661 jobid = atoi(argv[3]);
663 notify_job_status_byname(
664 messaging_event_context(msg_ctx), msg_ctx,
665 argv[2], jobid, JOB_STATUS_DELETING,
666 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
668 notify_job_status_byname(
669 messaging_event_context(msg_ctx), msg_ctx,
670 argv[2], jobid, JOB_STATUS_DELETING|
671 JOB_STATUS_DELETED,
672 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
674 goto send;
676 } else if (strcmp(cmd, "printer") == 0) {
677 uint32 attribute;
679 if (argc != 5) {
680 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
681 "printer <printername> <comment|port|driver> "
682 "<value>\n");
683 return False;
686 if (strcmp(argv[3], "comment") == 0) {
687 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
688 } else if (strcmp(argv[3], "port") == 0) {
689 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
690 } else if (strcmp(argv[3], "driver") == 0) {
691 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
692 } else {
693 fprintf(stderr, "Invalid printer command '%s'\n",
694 argv[3]);
695 return False;
698 notify_printer_byname(messaging_event_context(msg_ctx),
699 msg_ctx, argv[2], attribute,
700 CONST_DISCARD(char *, argv[4]));
702 goto send;
705 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
706 return False;
708 send:
709 print_notify_send_messages(msg_ctx, 0);
710 return True;
713 /* Close a share */
715 static bool do_closeshare(struct messaging_context *msg_ctx,
716 const struct server_id pid,
717 const int argc, const char **argv)
719 if (argc != 2) {
720 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
721 "<sharename>\n");
722 return False;
725 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
726 strlen(argv[1]) + 1);
729 /* Tell winbindd an IP got dropped */
731 static bool do_ip_dropped(struct messaging_context *msg_ctx,
732 const struct server_id pid,
733 const int argc, const char **argv)
735 if (argc != 2) {
736 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
737 "<ip-address>\n");
738 return False;
741 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
742 strlen(argv[1]) + 1);
745 /* force a blocking lock retry */
747 static bool do_lockretry(struct messaging_context *msg_ctx,
748 const struct server_id pid,
749 const int argc, const char **argv)
751 if (argc != 1) {
752 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
753 return False;
756 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
759 /* force a validation of all brl entries, including re-sends. */
761 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
762 const struct server_id pid,
763 const int argc, const char **argv)
765 if (argc != 1) {
766 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
767 return False;
770 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
773 /* Force a SAM synchronisation */
775 static bool do_samsync(struct messaging_context *msg_ctx,
776 const struct server_id pid,
777 const int argc, const char **argv)
779 if (argc != 1) {
780 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
781 return False;
784 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
787 /* Force a SAM replication */
789 static bool do_samrepl(struct messaging_context *msg_ctx,
790 const struct server_id pid,
791 const int argc, const char **argv)
793 if (argc != 1) {
794 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
795 return False;
798 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
801 /* Display talloc pool usage */
803 static bool do_poolusage(struct messaging_context *msg_ctx,
804 const struct server_id pid,
805 const int argc, const char **argv)
807 if (argc != 1) {
808 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
809 return False;
812 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
814 /* Send a message and register our interest in a reply */
816 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
817 return False;
819 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
821 /* No replies were received within the timeout period */
823 if (num_replies == 0)
824 printf("No replies received\n");
826 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
828 return num_replies;
831 /* Perform a dmalloc mark */
833 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
834 const struct server_id pid,
835 const int argc, const char **argv)
837 if (argc != 1) {
838 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
839 return False;
842 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
845 /* Perform a dmalloc changed */
847 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
848 const struct server_id pid,
849 const int argc, const char **argv)
851 if (argc != 1) {
852 fprintf(stderr, "Usage: smbcontrol <dest> "
853 "dmalloc-log-changed\n");
854 return False;
857 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
858 NULL, 0);
861 /* Shutdown a server process */
863 static bool do_shutdown(struct messaging_context *msg_ctx,
864 const struct server_id pid,
865 const int argc, const char **argv)
867 if (argc != 1) {
868 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
869 return False;
872 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
875 /* Notify a driver upgrade */
877 static bool do_drvupgrade(struct messaging_context *msg_ctx,
878 const struct server_id pid,
879 const int argc, const char **argv)
881 if (argc != 2) {
882 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
883 "<driver-name>\n");
884 return False;
887 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
888 strlen(argv[1]) + 1);
891 static bool do_winbind_online(struct messaging_context *msg_ctx,
892 const struct server_id pid,
893 const int argc, const char **argv)
895 TDB_CONTEXT *tdb;
897 if (argc != 1) {
898 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
899 return False;
902 /* Remove the entry in the winbindd_cache tdb to tell a later
903 starting winbindd that we're online. */
905 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
906 if (!tdb) {
907 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
908 cache_path("winbindd_cache.tdb"));
909 return False;
912 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
913 tdb_close(tdb);
915 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
918 static bool do_winbind_offline(struct messaging_context *msg_ctx,
919 const struct server_id pid,
920 const int argc, const char **argv)
922 TDB_CONTEXT *tdb;
923 bool ret = False;
924 int retry = 0;
926 if (argc != 1) {
927 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
928 return False;
931 /* Create an entry in the winbindd_cache tdb to tell a later
932 starting winbindd that we're offline. We may actually create
933 it here... */
935 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
936 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
937 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
938 O_RDWR|O_CREAT, 0600);
940 if (!tdb) {
941 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
942 cache_path("winbindd_cache.tdb"));
943 return False;
946 /* There's a potential race condition that if a child
947 winbindd detects a domain is online at the same time
948 we're trying to tell it to go offline that it might
949 delete the record we add between us adding it and
950 sending the message. Minimize this by retrying up to
951 5 times. */
953 for (retry = 0; retry < 5; retry++) {
954 TDB_DATA d;
955 uint8 buf[4];
957 ZERO_STRUCT(d);
959 SIVAL(buf, 0, time(NULL));
960 d.dptr = buf;
961 d.dsize = 4;
963 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
965 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
966 NULL, 0);
968 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
969 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
971 if (!d.dptr || d.dsize != 4) {
972 SAFE_FREE(d.dptr);
973 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
974 } else {
975 SAFE_FREE(d.dptr);
976 break;
980 tdb_close(tdb);
981 return ret;
984 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
985 const struct server_id pid,
986 const int argc, const char **argv)
988 struct server_id myid;
990 myid = messaging_server_id(msg_ctx);
992 if (argc != 1) {
993 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
994 return False;
997 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
998 print_pid_string_cb);
1000 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1001 sizeof(myid)))
1002 return False;
1004 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1006 /* No replies were received within the timeout period */
1008 if (num_replies == 0)
1009 printf("No replies received\n");
1011 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1013 return num_replies;
1016 static bool do_dump_event_list(struct messaging_context *msg_ctx,
1017 const struct server_id pid,
1018 const int argc, const char **argv)
1020 struct server_id myid;
1022 myid = messaging_server_id(msg_ctx);
1024 if (argc != 1) {
1025 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1026 return False;
1029 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1032 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1033 const struct server_id pid,
1034 const int argc, const char **argv)
1036 const char *domain = NULL;
1037 int domain_len = 0;
1038 struct server_id myid;
1039 uint8_t *buf = NULL;
1040 int buf_len = 0;
1042 myid = messaging_server_id(msg_ctx);
1044 if (argc < 1 || argc > 2) {
1045 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1046 "<domain>\n");
1047 return false;
1050 if (argc == 2) {
1051 domain = argv[1];
1052 domain_len = strlen(argv[1]) + 1;
1055 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1056 print_pid_string_cb);
1058 buf_len = sizeof(myid)+domain_len;
1059 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1060 if (!buf) {
1061 return false;
1064 memcpy(buf, &myid, sizeof(myid));
1065 memcpy(&buf[sizeof(myid)], domain, domain_len);
1067 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1068 buf, buf_len))
1070 SAFE_FREE(buf);
1071 return false;
1074 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1076 /* No replies were received within the timeout period */
1078 SAFE_FREE(buf);
1079 if (num_replies == 0) {
1080 printf("No replies received\n");
1083 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1085 return num_replies;
1088 static void winbind_validate_cache_cb(struct messaging_context *msg,
1089 void *private_data,
1090 uint32_t msg_type,
1091 struct server_id pid,
1092 DATA_BLOB *data)
1094 char *src_string = procid_str(NULL, &pid);
1095 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1096 (*(data->data) == 0 ? "" : "NOT "), src_string);
1097 TALLOC_FREE(src_string);
1098 num_replies++;
1101 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1102 const struct server_id pid,
1103 const int argc, const char **argv)
1105 struct server_id myid;
1107 myid = messaging_server_id(msg_ctx);
1109 if (argc != 1) {
1110 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1111 return False;
1114 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1115 winbind_validate_cache_cb);
1117 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1118 sizeof(myid))) {
1119 return False;
1122 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1124 if (num_replies == 0) {
1125 printf("No replies received\n");
1128 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1130 return num_replies;
1133 static bool do_reload_config(struct messaging_context *msg_ctx,
1134 const struct server_id pid,
1135 const int argc, const char **argv)
1137 if (argc != 1) {
1138 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1139 return False;
1142 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1145 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1147 fstring unix_name;
1148 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1149 fstrcpy(unix_name, name);
1150 strupper_m(unix_name);
1151 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1152 n->name_type = (unsigned int)type & 0xFF;
1153 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1156 static bool do_nodestatus(struct messaging_context *msg_ctx,
1157 const struct server_id pid,
1158 const int argc, const char **argv)
1160 struct packet_struct p;
1162 if (argc != 2) {
1163 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1164 return False;
1167 ZERO_STRUCT(p);
1169 p.ip = interpret_addr2(argv[1]);
1170 p.port = 137;
1171 p.packet_type = NMB_PACKET;
1173 p.packet.nmb.header.name_trn_id = 10;
1174 p.packet.nmb.header.opcode = 0;
1175 p.packet.nmb.header.response = False;
1176 p.packet.nmb.header.nm_flags.bcast = False;
1177 p.packet.nmb.header.nm_flags.recursion_available = False;
1178 p.packet.nmb.header.nm_flags.recursion_desired = False;
1179 p.packet.nmb.header.nm_flags.trunc = False;
1180 p.packet.nmb.header.nm_flags.authoritative = False;
1181 p.packet.nmb.header.rcode = 0;
1182 p.packet.nmb.header.qdcount = 1;
1183 p.packet.nmb.header.ancount = 0;
1184 p.packet.nmb.header.nscount = 0;
1185 p.packet.nmb.header.arcount = 0;
1186 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1187 p.packet.nmb.question.question_type = 0x21;
1188 p.packet.nmb.question.question_class = 0x1;
1190 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1193 /* A list of message type supported */
1195 static const struct {
1196 const char *name; /* Option name */
1197 bool (*fn)(struct messaging_context *msg_ctx,
1198 const struct server_id pid,
1199 const int argc, const char **argv);
1200 const char *help; /* Short help text */
1201 } msg_types[] = {
1202 { "debug", do_debug, "Set debuglevel" },
1203 { "force-election", do_election,
1204 "Force a browse election" },
1205 { "ping", do_ping, "Elicit a response" },
1206 { "profile", do_profile, "" },
1207 { "inject", do_inject_fault,
1208 "Inject a fatal signal into a running smbd"},
1209 { "stacktrace", do_daemon_stack_trace,
1210 "Display a stack trace of a daemon" },
1211 { "profilelevel", do_profilelevel, "" },
1212 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1213 { "printnotify", do_printnotify, "Send a print notify message" },
1214 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1215 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1216 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1217 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1218 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1219 { "samrepl", do_samrepl, "Initiate SAM replication" },
1220 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1221 { "dmalloc-mark", do_dmalloc_mark, "" },
1222 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1223 { "shutdown", do_shutdown, "Shut down daemon" },
1224 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1225 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1226 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1227 { "online", do_winbind_online, "Ask winbind to go into online state"},
1228 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1229 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1230 { "dump-event-list", do_dump_event_list, "Dump event list"},
1231 { "validate-cache" , do_winbind_validate_cache,
1232 "Validate winbind's credential cache" },
1233 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1234 { "noop", do_noop, "Do nothing" },
1235 { NULL }
1238 /* Display usage information */
1240 static void usage(poptContext pc)
1242 int i;
1244 poptPrintHelp(pc, stderr, 0);
1246 fprintf(stderr, "\n");
1247 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1248 "process ID\n");
1250 fprintf(stderr, "\n");
1251 fprintf(stderr, "<message-type> is one of:\n");
1253 for (i = 0; msg_types[i].name; i++)
1254 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1255 msg_types[i].help);
1257 fprintf(stderr, "\n");
1259 exit(1);
1262 /* Return the pid number for a string destination */
1264 static struct server_id parse_dest(struct messaging_context *msg,
1265 const char *dest)
1267 struct server_id result = {-1};
1268 pid_t pid;
1270 /* Zero is a special return value for broadcast to all processes */
1272 if (strequal(dest, "all")) {
1273 return interpret_pid(MSG_BROADCAST_PID_STR);
1276 /* Try self - useful for testing */
1278 if (strequal(dest, "self")) {
1279 return messaging_server_id(msg);
1282 /* Fix winbind typo. */
1283 if (strequal(dest, "winbind")) {
1284 dest = "winbindd";
1287 /* Check for numeric pid number */
1288 result = interpret_pid(dest);
1290 /* Zero isn't valid if not "all". */
1291 if (result.pid && procid_valid(&result)) {
1292 return result;
1295 /* Look up other destinations in pidfile directory */
1297 if ((pid = pidfile_pid(dest)) != 0) {
1298 return pid_to_procid(pid);
1301 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1303 return result;
1306 /* Execute smbcontrol command */
1308 static bool do_command(struct messaging_context *msg_ctx,
1309 int argc, const char **argv)
1311 const char *dest = argv[0], *command = argv[1];
1312 struct server_id pid;
1313 int i;
1315 /* Check destination */
1317 pid = parse_dest(msg_ctx, dest);
1318 if (!procid_valid(&pid)) {
1319 return False;
1322 /* Check command */
1324 for (i = 0; msg_types[i].name; i++) {
1325 if (strequal(command, msg_types[i].name))
1326 return msg_types[i].fn(msg_ctx, pid,
1327 argc - 1, argv + 1);
1330 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1332 return False;
1335 static void smbcontrol_help(poptContext pc,
1336 enum poptCallbackReason preason,
1337 struct poptOption * poption,
1338 const char * parg,
1339 void * pdata)
1341 if (poption->shortName != '?') {
1342 poptPrintUsage(pc, stdout, 0);
1343 } else {
1344 usage(pc);
1347 exit(0);
1350 struct poptOption help_options[] = {
1351 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1352 NULL, NULL },
1353 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1354 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1355 { NULL }
1358 /* Main program */
1360 int main(int argc, const char **argv)
1362 poptContext pc;
1363 int opt;
1364 struct tevent_context *evt_ctx;
1365 struct messaging_context *msg_ctx;
1367 static struct poptOption long_options[] = {
1368 /* POPT_AUTOHELP */
1369 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1370 0, "Help options:", NULL },
1371 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1372 "Set timeout value in seconds", "TIMEOUT" },
1374 POPT_COMMON_SAMBA
1375 POPT_TABLEEND
1377 TALLOC_CTX *frame = talloc_stackframe();
1378 int ret = 0;
1380 load_case_tables();
1382 setup_logging(argv[0], DEBUG_STDOUT);
1384 /* Parse command line arguments using popt */
1386 pc = poptGetContext(
1387 "smbcontrol", argc, (const char **)argv, long_options, 0);
1389 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1390 "<parameters>");
1392 if (argc == 1)
1393 usage(pc);
1395 while ((opt = poptGetNextOpt(pc)) != -1) {
1396 switch(opt) {
1397 case 't': /* --timeout */
1398 break;
1399 default:
1400 fprintf(stderr, "Invalid option\n");
1401 poptPrintHelp(pc, stderr, 0);
1402 break;
1406 /* We should now have the remaining command line arguments in
1407 argv. The argc parameter should have been decremented to the
1408 correct value in the above switch statement. */
1410 argv = (const char **)poptGetArgs(pc);
1411 argc = 0;
1412 if (argv != NULL) {
1413 while (argv[argc] != NULL) {
1414 argc++;
1418 if (argc <= 1)
1419 usage(pc);
1421 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1423 /* Need to invert sense of return code -- samba
1424 * routines mostly return True==1 for success, but
1425 * shell needs 0. */
1427 if (!(evt_ctx = tevent_context_init(NULL)) ||
1428 !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1429 fprintf(stderr, "could not init messaging context\n");
1430 TALLOC_FREE(frame);
1431 exit(1);
1434 ret = !do_command(msg_ctx, argc, argv);
1435 TALLOC_FREE(frame);
1436 return ret;