Revert "s3: Add sys_statvfs() wrapper support for OpenBSD/FreeBSD/DragonFly."
[Samba.git] / source3 / utils / smbcontrol.c
blob2759136657a0dd81afca5602327d85945a18c880
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 "system/filesys.h"
28 #include "popt_common.h"
29 #include "librpc/gen_ndr/spoolss.h"
30 #include "nt_printing.h"
31 #include "printing/notify.h"
32 #include "libsmb/nmblib.h"
33 #include "messages.h"
34 #include "util_tdb.h"
36 #if HAVE_LIBUNWIND_H
37 #include <libunwind.h>
38 #endif
40 #if HAVE_LIBUNWIND_PTRACE_H
41 #include <libunwind-ptrace.h>
42 #endif
44 #if HAVE_SYS_PTRACE_H
45 #include <sys/ptrace.h>
46 #endif
48 /* Default timeout value when waiting for replies (in seconds) */
50 #define DEFAULT_TIMEOUT 10
52 static int timeout = DEFAULT_TIMEOUT;
53 static int num_replies; /* Used by message callback fns */
55 /* Send a message to a destination pid. Zero means broadcast smbd. */
57 static bool send_message(struct messaging_context *msg_ctx,
58 struct server_id pid, int msg_type,
59 const void *buf, int len)
61 bool ret;
62 int n_sent = 0;
64 if (procid_to_pid(&pid) != 0)
65 return NT_STATUS_IS_OK(
66 messaging_send_buf(msg_ctx, pid, msg_type,
67 (uint8 *)buf, len));
69 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
70 DEBUG(10,("smbcontrol/send_message: broadcast message to "
71 "%d processes\n", n_sent));
73 return ret;
76 static void smbcontrol_timeout(struct tevent_context *event_ctx,
77 struct tevent_timer *te,
78 struct timeval now,
79 void *private_data)
81 bool *timed_out = (bool *)private_data;
82 TALLOC_FREE(te);
83 *timed_out = True;
86 /* Wait for one or more reply messages */
88 static void wait_replies(struct messaging_context *msg_ctx,
89 bool multiple_replies)
91 struct tevent_timer *te;
92 bool timed_out = False;
94 if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
95 timeval_current_ofs(timeout, 0),
96 smbcontrol_timeout, (void *)&timed_out))) {
97 DEBUG(0, ("tevent_add_timer failed\n"));
98 return;
101 while (!timed_out) {
102 int ret;
103 if (num_replies > 0 && !multiple_replies)
104 break;
105 ret = tevent_loop_once(messaging_event_context(msg_ctx));
106 if (ret != 0) {
107 break;
112 /* Message handler callback that displays the PID and a string on stdout */
114 static void print_pid_string_cb(struct messaging_context *msg,
115 void *private_data,
116 uint32_t msg_type,
117 struct server_id pid,
118 DATA_BLOB *data)
120 char *pidstr;
122 pidstr = procid_str(talloc_tos(), &pid);
123 printf("PID %s: %.*s", pidstr, (int)data->length,
124 (const char *)data->data);
125 TALLOC_FREE(pidstr);
126 num_replies++;
129 /* Message handler callback that displays a string on stdout */
131 static void print_string_cb(struct messaging_context *msg,
132 void *private_data,
133 uint32_t msg_type,
134 struct server_id pid,
135 DATA_BLOB *data)
137 printf("%*s", (int)data->length, (const char *)data->data);
138 num_replies++;
141 /* Send no message. Useful for testing. */
143 static bool do_noop(struct messaging_context *msg_ctx,
144 const struct server_id pid,
145 const int argc, const char **argv)
147 if (argc != 1) {
148 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
149 return False;
152 /* Move along, nothing to see here */
154 return True;
157 /* Send a debug string */
159 static bool do_debug(struct messaging_context *msg_ctx,
160 const struct server_id pid,
161 const int argc, const char **argv)
163 if (argc != 2) {
164 fprintf(stderr, "Usage: smbcontrol <dest> debug "
165 "<debug-string>\n");
166 return False;
169 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
170 strlen(argv[1]) + 1);
174 static bool do_idmap(struct messaging_context *msg_ctx,
175 const struct server_id pid,
176 const int argc, const char **argv)
178 static const char* usage = "Usage: "
179 "smbcontrol <dest> idmap <cmd> [arg]\n"
180 "\tcmd:\tflush [gid|uid]\n"
181 "\t\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
182 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
183 const char* arg = NULL;
184 int arglen = 0;
185 int msg_type;
187 switch (argc) {
188 case 2:
189 break;
190 case 3:
191 arg = argv[2];
192 arglen = strlen(arg) + 1;
193 break;
194 default:
195 fprintf(stderr, "%s", usage);
196 return false;
199 if (strcmp(argv[1], "flush") == 0) {
200 msg_type = MSG_IDMAP_FLUSH;
202 else if (strcmp(argv[1], "delete") == 0) {
203 msg_type = MSG_IDMAP_DELETE;
205 else if (strcmp(argv[1], "kill") == 0) {
206 msg_type = MSG_IDMAP_KILL;
208 else if (strcmp(argv[1], "help") == 0) {
209 fprintf(stdout, "%s", usage);
210 return true;
212 else {
213 fprintf(stderr, "%s", usage);
214 return false;
217 return send_message(msg_ctx, pid, msg_type, arg, arglen);
221 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
223 /* Return the name of a process given it's PID. This will only work on Linux,
224 * but that's probably moot since this whole stack tracing implementatino is
225 * Linux-specific anyway.
227 static const char * procname(pid_t pid, char * buf, size_t bufsz)
229 char path[64];
230 FILE * fp;
232 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
233 (unsigned long long)pid);
234 if ((fp = fopen(path, "r")) == NULL) {
235 return NULL;
238 fgets(buf, bufsz, fp);
240 fclose(fp);
241 return buf;
244 static void print_stack_trace(pid_t pid, int * count)
246 void * pinfo = NULL;
247 unw_addr_space_t aspace = NULL;
248 unw_cursor_t cursor;
249 unw_word_t ip, sp;
251 char nbuf[256];
252 unw_word_t off;
254 int ret;
256 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
257 fprintf(stderr,
258 "Failed to attach to process %llu: %s\n",
259 (unsigned long long)pid, strerror(errno));
260 return;
263 /* Wait until the attach is complete. */
264 waitpid(pid, NULL, 0);
266 if (((pinfo = _UPT_create(pid)) == NULL) ||
267 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
268 /* Probably out of memory. */
269 fprintf(stderr,
270 "Unable to initialize stack unwind for process %llu\n",
271 (unsigned long long)pid);
272 goto cleanup;
275 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
276 fprintf(stderr,
277 "Unable to unwind stack for process %llu: %s\n",
278 (unsigned long long)pid, unw_strerror(ret));
279 goto cleanup;
282 if (*count > 0) {
283 printf("\n");
286 if (procname(pid, nbuf, sizeof(nbuf))) {
287 printf("Stack trace for process %llu (%s):\n",
288 (unsigned long long)pid, nbuf);
289 } else {
290 printf("Stack trace for process %llu:\n",
291 (unsigned long long)pid);
294 while (unw_step(&cursor) > 0) {
295 ip = sp = off = 0;
296 unw_get_reg(&cursor, UNW_REG_IP, &ip);
297 unw_get_reg(&cursor, UNW_REG_SP, &sp);
299 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
300 if (ret != 0 && ret != -UNW_ENOMEM) {
301 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
303 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
304 nbuf, (long long)off, (long long)ip,
305 (long long)sp);
308 (*count)++;
310 cleanup:
311 if (aspace) {
312 unw_destroy_addr_space(aspace);
315 if (pinfo) {
316 _UPT_destroy(pinfo);
319 ptrace(PTRACE_DETACH, pid, NULL, NULL);
322 static int stack_trace_connection(const struct connections_key *key,
323 const struct connections_data *crec,
324 void *priv)
326 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
328 return 0;
331 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
332 const struct server_id pid,
333 const int argc, const char **argv)
335 pid_t dest;
336 int count = 0;
338 if (argc != 1) {
339 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
340 return False;
343 dest = procid_to_pid(&pid);
345 if (dest != 0) {
346 /* It would be nice to be able to make sure that this PID is
347 * the PID of a smbd/winbind/nmbd process, not some random PID
348 * the user liked the look of. It doesn't seem like it's worth
349 * the effort at the moment, however.
351 print_stack_trace(dest, &count);
352 } else {
353 connections_forall_read(stack_trace_connection, &count);
356 return True;
359 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
361 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
362 const struct server_id pid,
363 const int argc, const char **argv)
365 fprintf(stderr,
366 "Daemon stack tracing is not supported on this platform\n");
367 return False;
370 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
372 /* Inject a fault (fatal signal) into a running smbd */
374 static bool do_inject_fault(struct messaging_context *msg_ctx,
375 const struct server_id pid,
376 const int argc, const char **argv)
378 if (argc != 2) {
379 fprintf(stderr, "Usage: smbcontrol <dest> inject "
380 "<bus|hup|term|internal|segv>\n");
381 return False;
384 #ifndef DEVELOPER
385 fprintf(stderr, "Fault injection is only available in "
386 "developer builds\n");
387 return False;
388 #else /* DEVELOPER */
390 int sig = 0;
392 if (strcmp(argv[1], "bus") == 0) {
393 sig = SIGBUS;
394 } else if (strcmp(argv[1], "hup") == 0) {
395 sig = SIGHUP;
396 } else if (strcmp(argv[1], "term") == 0) {
397 sig = SIGTERM;
398 } else if (strcmp(argv[1], "segv") == 0) {
399 sig = SIGSEGV;
400 } else if (strcmp(argv[1], "internal") == 0) {
401 /* Force an internal error, ie. an unclean exit. */
402 sig = -1;
403 } else {
404 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
405 return False;
408 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
409 &sig, sizeof(int));
411 #endif /* DEVELOPER */
414 /* Force a browser election */
416 static bool do_election(struct messaging_context *msg_ctx,
417 const struct server_id pid,
418 const int argc, const char **argv)
420 if (argc != 1) {
421 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
422 return False;
425 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
428 /* Ping a samba daemon process */
430 static void pong_cb(struct messaging_context *msg,
431 void *private_data,
432 uint32_t msg_type,
433 struct server_id pid,
434 DATA_BLOB *data)
436 char *src_string = procid_str(NULL, &pid);
437 printf("PONG from pid %s\n", src_string);
438 TALLOC_FREE(src_string);
439 num_replies++;
442 static bool do_ping(struct messaging_context *msg_ctx,
443 const struct server_id pid,
444 const int argc, const char **argv)
446 if (argc != 1) {
447 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
448 return False;
451 /* Send a message and register our interest in a reply */
453 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
454 return False;
456 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
458 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
460 /* No replies were received within the timeout period */
462 if (num_replies == 0)
463 printf("No replies received\n");
465 messaging_deregister(msg_ctx, MSG_PONG, NULL);
467 return num_replies;
470 /* Set profiling options */
472 static bool do_profile(struct messaging_context *msg_ctx,
473 const struct server_id pid,
474 const int argc, const char **argv)
476 int v;
478 if (argc != 2) {
479 fprintf(stderr, "Usage: smbcontrol <dest> profile "
480 "<off|count|on|flush>\n");
481 return False;
484 if (strcmp(argv[1], "off") == 0) {
485 v = 0;
486 } else if (strcmp(argv[1], "count") == 0) {
487 v = 1;
488 } else if (strcmp(argv[1], "on") == 0) {
489 v = 2;
490 } else if (strcmp(argv[1], "flush") == 0) {
491 v = 3;
492 } else {
493 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
494 return False;
497 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
500 /* Return the profiling level */
502 static void profilelevel_cb(struct messaging_context *msg_ctx,
503 void *private_data,
504 uint32_t msg_type,
505 struct server_id pid,
506 DATA_BLOB *data)
508 int level;
509 const char *s;
511 num_replies++;
513 if (data->length != sizeof(int)) {
514 fprintf(stderr, "invalid message length %ld returned\n",
515 (unsigned long)data->length);
516 return;
519 memcpy(&level, data->data, sizeof(int));
521 switch (level) {
522 case 0:
523 s = "not enabled";
524 break;
525 case 1:
526 s = "off";
527 break;
528 case 3:
529 s = "count only";
530 break;
531 case 7:
532 s = "count and time";
533 break;
534 default:
535 s = "BOGUS";
536 break;
539 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
542 static void profilelevel_rqst(struct messaging_context *msg_ctx,
543 void *private_data,
544 uint32_t msg_type,
545 struct server_id pid,
546 DATA_BLOB *data)
548 int v = 0;
550 /* Send back a dummy reply */
552 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
555 static bool do_profilelevel(struct messaging_context *msg_ctx,
556 const struct server_id pid,
557 const int argc, const char **argv)
559 if (argc != 1) {
560 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
561 return False;
564 /* Send a message and register our interest in a reply */
566 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
567 return False;
569 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
570 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
571 profilelevel_rqst);
573 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
575 /* No replies were received within the timeout period */
577 if (num_replies == 0)
578 printf("No replies received\n");
580 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
582 return num_replies;
585 /* Display debug level settings */
587 static bool do_debuglevel(struct messaging_context *msg_ctx,
588 const struct server_id pid,
589 const int argc, const char **argv)
591 if (argc != 1) {
592 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
593 return False;
596 /* Send a message and register our interest in a reply */
598 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
599 return False;
601 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
603 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
605 /* No replies were received within the timeout period */
607 if (num_replies == 0)
608 printf("No replies received\n");
610 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
612 return num_replies;
615 /* Send a print notify message */
617 static bool do_printnotify(struct messaging_context *msg_ctx,
618 const struct server_id pid,
619 const int argc, const char **argv)
621 const char *cmd;
623 /* Check for subcommand */
625 if (argc == 1) {
626 fprintf(stderr, "Must specify subcommand:\n");
627 fprintf(stderr, "\tqueuepause <printername>\n");
628 fprintf(stderr, "\tqueueresume <printername>\n");
629 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
630 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
631 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
632 fprintf(stderr, "\tprinter <printername> <comment|port|"
633 "driver> <value>\n");
635 return False;
638 cmd = argv[1];
640 if (strcmp(cmd, "queuepause") == 0) {
642 if (argc != 3) {
643 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
644 " queuepause <printername>\n");
645 return False;
648 notify_printer_status_byname(messaging_event_context(msg_ctx),
649 msg_ctx, argv[2],
650 PRINTER_STATUS_PAUSED);
652 goto send;
654 } else if (strcmp(cmd, "queueresume") == 0) {
656 if (argc != 3) {
657 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
658 " queuereume <printername>\n");
659 return False;
662 notify_printer_status_byname(messaging_event_context(msg_ctx),
663 msg_ctx, argv[2],
664 PRINTER_STATUS_OK);
666 goto send;
668 } else if (strcmp(cmd, "jobpause") == 0) {
669 int jobid;
671 if (argc != 4) {
672 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
673 " jobpause <printername> <unix-jobid>\n");
674 return False;
677 jobid = atoi(argv[3]);
679 notify_job_status_byname(
680 messaging_event_context(msg_ctx), msg_ctx,
681 argv[2], jobid, JOB_STATUS_PAUSED,
682 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
684 goto send;
686 } else if (strcmp(cmd, "jobresume") == 0) {
687 int jobid;
689 if (argc != 4) {
690 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
691 " jobpause <printername> <unix-jobid>\n");
692 return False;
695 jobid = atoi(argv[3]);
697 notify_job_status_byname(
698 messaging_event_context(msg_ctx), msg_ctx,
699 argv[2], jobid, JOB_STATUS_QUEUED,
700 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
702 goto send;
704 } else if (strcmp(cmd, "jobdelete") == 0) {
705 int jobid;
707 if (argc != 4) {
708 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
709 " jobpause <printername> <unix-jobid>\n");
710 return False;
713 jobid = atoi(argv[3]);
715 notify_job_status_byname(
716 messaging_event_context(msg_ctx), msg_ctx,
717 argv[2], jobid, JOB_STATUS_DELETING,
718 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
720 notify_job_status_byname(
721 messaging_event_context(msg_ctx), msg_ctx,
722 argv[2], jobid, JOB_STATUS_DELETING|
723 JOB_STATUS_DELETED,
724 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
726 goto send;
728 } else if (strcmp(cmd, "printer") == 0) {
729 uint32 attribute;
731 if (argc != 5) {
732 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
733 "printer <printername> <comment|port|driver> "
734 "<value>\n");
735 return False;
738 if (strcmp(argv[3], "comment") == 0) {
739 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
740 } else if (strcmp(argv[3], "port") == 0) {
741 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
742 } else if (strcmp(argv[3], "driver") == 0) {
743 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
744 } else {
745 fprintf(stderr, "Invalid printer command '%s'\n",
746 argv[3]);
747 return False;
750 notify_printer_byname(messaging_event_context(msg_ctx),
751 msg_ctx, argv[2], attribute,
752 CONST_DISCARD(char *, argv[4]));
754 goto send;
757 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
758 return False;
760 send:
761 print_notify_send_messages(msg_ctx, 0);
762 return True;
765 /* Close a share */
767 static bool do_closeshare(struct messaging_context *msg_ctx,
768 const struct server_id pid,
769 const int argc, const char **argv)
771 if (argc != 2) {
772 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
773 "<sharename>\n");
774 return False;
777 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
778 strlen(argv[1]) + 1);
781 /* Tell winbindd an IP got dropped */
783 static bool do_ip_dropped(struct messaging_context *msg_ctx,
784 const struct server_id pid,
785 const int argc, const char **argv)
787 if (argc != 2) {
788 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
789 "<ip-address>\n");
790 return False;
793 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
794 strlen(argv[1]) + 1);
797 /* force a blocking lock retry */
799 static bool do_lockretry(struct messaging_context *msg_ctx,
800 const struct server_id pid,
801 const int argc, const char **argv)
803 if (argc != 1) {
804 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
805 return False;
808 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
811 /* force a validation of all brl entries, including re-sends. */
813 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
814 const struct server_id pid,
815 const int argc, const char **argv)
817 if (argc != 1) {
818 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
819 return False;
822 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
825 /* Force a SAM synchronisation */
827 static bool do_samsync(struct messaging_context *msg_ctx,
828 const struct server_id pid,
829 const int argc, const char **argv)
831 if (argc != 1) {
832 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
833 return False;
836 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
839 /* Force a SAM replication */
841 static bool do_samrepl(struct messaging_context *msg_ctx,
842 const struct server_id pid,
843 const int argc, const char **argv)
845 if (argc != 1) {
846 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
847 return False;
850 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
853 /* Display talloc pool usage */
855 static bool do_poolusage(struct messaging_context *msg_ctx,
856 const struct server_id pid,
857 const int argc, const char **argv)
859 if (argc != 1) {
860 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
861 return False;
864 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
866 /* Send a message and register our interest in a reply */
868 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
869 return False;
871 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
873 /* No replies were received within the timeout period */
875 if (num_replies == 0)
876 printf("No replies received\n");
878 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
880 return num_replies;
883 /* Perform a dmalloc mark */
885 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
886 const struct server_id pid,
887 const int argc, const char **argv)
889 if (argc != 1) {
890 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
891 return False;
894 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
897 /* Perform a dmalloc changed */
899 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
900 const struct server_id pid,
901 const int argc, const char **argv)
903 if (argc != 1) {
904 fprintf(stderr, "Usage: smbcontrol <dest> "
905 "dmalloc-log-changed\n");
906 return False;
909 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
910 NULL, 0);
913 /* Shutdown a server process */
915 static bool do_shutdown(struct messaging_context *msg_ctx,
916 const struct server_id pid,
917 const int argc, const char **argv)
919 if (argc != 1) {
920 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
921 return False;
924 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
927 /* Notify a driver upgrade */
929 static bool do_drvupgrade(struct messaging_context *msg_ctx,
930 const struct server_id pid,
931 const int argc, const char **argv)
933 if (argc != 2) {
934 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
935 "<driver-name>\n");
936 return False;
939 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
940 strlen(argv[1]) + 1);
943 static bool do_winbind_online(struct messaging_context *msg_ctx,
944 const struct server_id pid,
945 const int argc, const char **argv)
947 TDB_CONTEXT *tdb;
949 if (argc != 1) {
950 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
951 return False;
954 /* Remove the entry in the winbindd_cache tdb to tell a later
955 starting winbindd that we're online. */
957 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
958 if (!tdb) {
959 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
960 cache_path("winbindd_cache.tdb"));
961 return False;
964 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
965 tdb_close(tdb);
967 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
970 static bool do_winbind_offline(struct messaging_context *msg_ctx,
971 const struct server_id pid,
972 const int argc, const char **argv)
974 TDB_CONTEXT *tdb;
975 bool ret = False;
976 int retry = 0;
978 if (argc != 1) {
979 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
980 return False;
983 /* Create an entry in the winbindd_cache tdb to tell a later
984 starting winbindd that we're offline. We may actually create
985 it here... */
987 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
988 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
989 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
990 O_RDWR|O_CREAT, 0600);
992 if (!tdb) {
993 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
994 cache_path("winbindd_cache.tdb"));
995 return False;
998 /* There's a potential race condition that if a child
999 winbindd detects a domain is online at the same time
1000 we're trying to tell it to go offline that it might
1001 delete the record we add between us adding it and
1002 sending the message. Minimize this by retrying up to
1003 5 times. */
1005 for (retry = 0; retry < 5; retry++) {
1006 TDB_DATA d;
1007 uint8 buf[4];
1009 ZERO_STRUCT(d);
1011 SIVAL(buf, 0, time(NULL));
1012 d.dptr = buf;
1013 d.dsize = 4;
1015 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1017 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1018 NULL, 0);
1020 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1021 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1023 if (!d.dptr || d.dsize != 4) {
1024 SAFE_FREE(d.dptr);
1025 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1026 } else {
1027 SAFE_FREE(d.dptr);
1028 break;
1032 tdb_close(tdb);
1033 return ret;
1036 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
1037 const struct server_id pid,
1038 const int argc, const char **argv)
1040 struct server_id myid;
1042 myid = messaging_server_id(msg_ctx);
1044 if (argc != 1) {
1045 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1046 return False;
1049 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1050 print_pid_string_cb);
1052 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1053 sizeof(myid)))
1054 return False;
1056 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1058 /* No replies were received within the timeout period */
1060 if (num_replies == 0)
1061 printf("No replies received\n");
1063 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1065 return num_replies;
1068 static bool do_dump_event_list(struct messaging_context *msg_ctx,
1069 const struct server_id pid,
1070 const int argc, const char **argv)
1072 struct server_id myid;
1074 myid = messaging_server_id(msg_ctx);
1076 if (argc != 1) {
1077 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1078 return False;
1081 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1084 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1085 const struct server_id pid,
1086 const int argc, const char **argv)
1088 const char *domain = NULL;
1089 int domain_len = 0;
1090 struct server_id myid;
1091 uint8_t *buf = NULL;
1092 int buf_len = 0;
1094 myid = messaging_server_id(msg_ctx);
1096 if (argc < 1 || argc > 2) {
1097 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1098 "<domain>\n");
1099 return false;
1102 if (argc == 2) {
1103 domain = argv[1];
1104 domain_len = strlen(argv[1]) + 1;
1107 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1108 print_pid_string_cb);
1110 buf_len = sizeof(myid)+domain_len;
1111 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1112 if (!buf) {
1113 return false;
1116 memcpy(buf, &myid, sizeof(myid));
1117 memcpy(&buf[sizeof(myid)], domain, domain_len);
1119 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1120 buf, buf_len))
1122 SAFE_FREE(buf);
1123 return false;
1126 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1128 /* No replies were received within the timeout period */
1130 SAFE_FREE(buf);
1131 if (num_replies == 0) {
1132 printf("No replies received\n");
1135 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1137 return num_replies;
1140 static void winbind_validate_cache_cb(struct messaging_context *msg,
1141 void *private_data,
1142 uint32_t msg_type,
1143 struct server_id pid,
1144 DATA_BLOB *data)
1146 char *src_string = procid_str(NULL, &pid);
1147 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1148 (*(data->data) == 0 ? "" : "NOT "), src_string);
1149 TALLOC_FREE(src_string);
1150 num_replies++;
1153 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1154 const struct server_id pid,
1155 const int argc, const char **argv)
1157 struct server_id myid;
1159 myid = messaging_server_id(msg_ctx);
1161 if (argc != 1) {
1162 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1163 return False;
1166 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1167 winbind_validate_cache_cb);
1169 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1170 sizeof(myid))) {
1171 return False;
1174 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1176 if (num_replies == 0) {
1177 printf("No replies received\n");
1180 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1182 return num_replies;
1185 static bool do_reload_config(struct messaging_context *msg_ctx,
1186 const struct server_id pid,
1187 const int argc, const char **argv)
1189 if (argc != 1) {
1190 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1191 return False;
1194 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1197 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1199 fstring unix_name;
1200 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1201 fstrcpy(unix_name, name);
1202 strupper_m(unix_name);
1203 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1204 n->name_type = (unsigned int)type & 0xFF;
1205 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1208 static bool do_nodestatus(struct messaging_context *msg_ctx,
1209 const struct server_id pid,
1210 const int argc, const char **argv)
1212 struct packet_struct p;
1214 if (argc != 2) {
1215 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1216 return False;
1219 ZERO_STRUCT(p);
1221 p.ip = interpret_addr2(argv[1]);
1222 p.port = 137;
1223 p.packet_type = NMB_PACKET;
1225 p.packet.nmb.header.name_trn_id = 10;
1226 p.packet.nmb.header.opcode = 0;
1227 p.packet.nmb.header.response = False;
1228 p.packet.nmb.header.nm_flags.bcast = False;
1229 p.packet.nmb.header.nm_flags.recursion_available = False;
1230 p.packet.nmb.header.nm_flags.recursion_desired = False;
1231 p.packet.nmb.header.nm_flags.trunc = False;
1232 p.packet.nmb.header.nm_flags.authoritative = False;
1233 p.packet.nmb.header.rcode = 0;
1234 p.packet.nmb.header.qdcount = 1;
1235 p.packet.nmb.header.ancount = 0;
1236 p.packet.nmb.header.nscount = 0;
1237 p.packet.nmb.header.arcount = 0;
1238 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1239 p.packet.nmb.question.question_type = 0x21;
1240 p.packet.nmb.question.question_class = 0x1;
1242 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1245 /* A list of message type supported */
1247 static const struct {
1248 const char *name; /* Option name */
1249 bool (*fn)(struct messaging_context *msg_ctx,
1250 const struct server_id pid,
1251 const int argc, const char **argv);
1252 const char *help; /* Short help text */
1253 } msg_types[] = {
1254 { "debug", do_debug, "Set debuglevel" },
1255 { "idmap", do_idmap, "Manipulate idmap cache" },
1256 { "force-election", do_election,
1257 "Force a browse election" },
1258 { "ping", do_ping, "Elicit a response" },
1259 { "profile", do_profile, "" },
1260 { "inject", do_inject_fault,
1261 "Inject a fatal signal into a running smbd"},
1262 { "stacktrace", do_daemon_stack_trace,
1263 "Display a stack trace of a daemon" },
1264 { "profilelevel", do_profilelevel, "" },
1265 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1266 { "printnotify", do_printnotify, "Send a print notify message" },
1267 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1268 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1269 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1270 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1271 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1272 { "samrepl", do_samrepl, "Initiate SAM replication" },
1273 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1274 { "dmalloc-mark", do_dmalloc_mark, "" },
1275 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1276 { "shutdown", do_shutdown, "Shut down daemon" },
1277 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1278 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1279 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1280 { "online", do_winbind_online, "Ask winbind to go into online state"},
1281 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1282 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1283 { "dump-event-list", do_dump_event_list, "Dump event list"},
1284 { "validate-cache" , do_winbind_validate_cache,
1285 "Validate winbind's credential cache" },
1286 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1287 { "noop", do_noop, "Do nothing" },
1288 { NULL }
1291 /* Display usage information */
1293 static void usage(poptContext pc)
1295 int i;
1297 poptPrintHelp(pc, stderr, 0);
1299 fprintf(stderr, "\n");
1300 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1301 "process ID\n");
1303 fprintf(stderr, "\n");
1304 fprintf(stderr, "<message-type> is one of:\n");
1306 for (i = 0; msg_types[i].name; i++)
1307 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1308 msg_types[i].help);
1310 fprintf(stderr, "\n");
1312 exit(1);
1315 /* Return the pid number for a string destination */
1317 static struct server_id parse_dest(struct messaging_context *msg,
1318 const char *dest)
1320 struct server_id result = {-1};
1321 pid_t pid;
1323 /* Zero is a special return value for broadcast to all processes */
1325 if (strequal(dest, "all")) {
1326 return interpret_pid(MSG_BROADCAST_PID_STR);
1329 /* Try self - useful for testing */
1331 if (strequal(dest, "self")) {
1332 return messaging_server_id(msg);
1335 /* Fix winbind typo. */
1336 if (strequal(dest, "winbind")) {
1337 dest = "winbindd";
1340 /* Check for numeric pid number */
1341 result = interpret_pid(dest);
1343 /* Zero isn't valid if not "all". */
1344 if (result.pid && procid_valid(&result)) {
1345 return result;
1348 /* Look up other destinations in pidfile directory */
1350 if ((pid = pidfile_pid(dest)) != 0) {
1351 return pid_to_procid(pid);
1354 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1356 return result;
1359 /* Execute smbcontrol command */
1361 static bool do_command(struct messaging_context *msg_ctx,
1362 int argc, const char **argv)
1364 const char *dest = argv[0], *command = argv[1];
1365 struct server_id pid;
1366 int i;
1368 /* Check destination */
1370 pid = parse_dest(msg_ctx, dest);
1371 if (!procid_valid(&pid)) {
1372 return False;
1375 /* Check command */
1377 for (i = 0; msg_types[i].name; i++) {
1378 if (strequal(command, msg_types[i].name))
1379 return msg_types[i].fn(msg_ctx, pid,
1380 argc - 1, argv + 1);
1383 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1385 return False;
1388 static void smbcontrol_help(poptContext pc,
1389 enum poptCallbackReason preason,
1390 struct poptOption * poption,
1391 const char * parg,
1392 void * pdata)
1394 if (poption->shortName != '?') {
1395 poptPrintUsage(pc, stdout, 0);
1396 } else {
1397 usage(pc);
1400 exit(0);
1403 struct poptOption help_options[] = {
1404 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1405 NULL, NULL },
1406 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1407 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1408 { NULL }
1411 /* Main program */
1413 int main(int argc, const char **argv)
1415 poptContext pc;
1416 int opt;
1417 struct tevent_context *evt_ctx;
1418 struct messaging_context *msg_ctx;
1420 static struct poptOption long_options[] = {
1421 /* POPT_AUTOHELP */
1422 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1423 0, "Help options:", NULL },
1424 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1425 "Set timeout value in seconds", "TIMEOUT" },
1427 POPT_COMMON_SAMBA
1428 POPT_TABLEEND
1430 TALLOC_CTX *frame = talloc_stackframe();
1431 int ret = 0;
1433 load_case_tables();
1435 setup_logging(argv[0], DEBUG_STDOUT);
1437 /* Parse command line arguments using popt */
1439 pc = poptGetContext(
1440 "smbcontrol", argc, (const char **)argv, long_options, 0);
1442 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1443 "<parameters>");
1445 if (argc == 1)
1446 usage(pc);
1448 while ((opt = poptGetNextOpt(pc)) != -1) {
1449 switch(opt) {
1450 case 't': /* --timeout */
1451 break;
1452 default:
1453 fprintf(stderr, "Invalid option\n");
1454 poptPrintHelp(pc, stderr, 0);
1455 break;
1459 /* We should now have the remaining command line arguments in
1460 argv. The argc parameter should have been decremented to the
1461 correct value in the above switch statement. */
1463 argv = (const char **)poptGetArgs(pc);
1464 argc = 0;
1465 if (argv != NULL) {
1466 while (argv[argc] != NULL) {
1467 argc++;
1471 if (argc <= 1)
1472 usage(pc);
1474 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1476 /* Need to invert sense of return code -- samba
1477 * routines mostly return True==1 for success, but
1478 * shell needs 0. */
1480 if (!(evt_ctx = tevent_context_init(NULL)) ||
1481 !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1482 fprintf(stderr, "could not init messaging context\n");
1483 TALLOC_FREE(frame);
1484 exit(1);
1487 ret = !do_command(msg_ctx, argc, argv);
1488 TALLOC_FREE(frame);
1489 return ret;