Change to using TDB_INCOMPATIBLE_HASH (the jenkins hash) on all
[Samba.git] / source3 / utils / smbcontrol.c
blob5bab324b6e342268f06ac45575f198db06a76bbe
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(argv[2], PRINTER_STATUS_PAUSED);
598 goto send;
600 } else if (strcmp(cmd, "queueresume") == 0) {
602 if (argc != 3) {
603 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
604 " queuereume <printername>\n");
605 return False;
608 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
610 goto send;
612 } else if (strcmp(cmd, "jobpause") == 0) {
613 int jobid;
615 if (argc != 4) {
616 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
617 " jobpause <printername> <unix-jobid>\n");
618 return False;
621 jobid = atoi(argv[3]);
623 notify_job_status_byname(
624 argv[2], jobid, JOB_STATUS_PAUSED,
625 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
627 goto send;
629 } else if (strcmp(cmd, "jobresume") == 0) {
630 int jobid;
632 if (argc != 4) {
633 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
634 " jobpause <printername> <unix-jobid>\n");
635 return False;
638 jobid = atoi(argv[3]);
640 notify_job_status_byname(
641 argv[2], jobid, JOB_STATUS_QUEUED,
642 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
644 goto send;
646 } else if (strcmp(cmd, "jobdelete") == 0) {
647 int jobid;
649 if (argc != 4) {
650 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
651 " jobpause <printername> <unix-jobid>\n");
652 return False;
655 jobid = atoi(argv[3]);
657 notify_job_status_byname(
658 argv[2], jobid, JOB_STATUS_DELETING,
659 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
661 notify_job_status_byname(
662 argv[2], jobid, JOB_STATUS_DELETING|
663 JOB_STATUS_DELETED,
664 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
666 goto send;
668 } else if (strcmp(cmd, "printer") == 0) {
669 uint32 attribute;
671 if (argc != 5) {
672 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
673 "printer <printername> <comment|port|driver> "
674 "<value>\n");
675 return False;
678 if (strcmp(argv[3], "comment") == 0) {
679 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
680 } else if (strcmp(argv[3], "port") == 0) {
681 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
682 } else if (strcmp(argv[3], "driver") == 0) {
683 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
684 } else {
685 fprintf(stderr, "Invalid printer command '%s'\n",
686 argv[3]);
687 return False;
690 notify_printer_byname(argv[2], attribute,
691 CONST_DISCARD(char *, argv[4]));
693 goto send;
696 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
697 return False;
699 send:
700 print_notify_send_messages(msg_ctx, 0);
701 return True;
704 /* Close a share */
706 static bool do_closeshare(struct messaging_context *msg_ctx,
707 const struct server_id pid,
708 const int argc, const char **argv)
710 if (argc != 2) {
711 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
712 "<sharename>\n");
713 return False;
716 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
717 strlen(argv[1]) + 1);
720 /* Tell winbindd an IP got dropped */
722 static bool do_ip_dropped(struct messaging_context *msg_ctx,
723 const struct server_id pid,
724 const int argc, const char **argv)
726 if (argc != 2) {
727 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
728 "<ip-address>\n");
729 return False;
732 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
733 strlen(argv[1]) + 1);
736 /* force a blocking lock retry */
738 static bool do_lockretry(struct messaging_context *msg_ctx,
739 const struct server_id pid,
740 const int argc, const char **argv)
742 if (argc != 1) {
743 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
744 return False;
747 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
750 /* force a validation of all brl entries, including re-sends. */
752 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
753 const struct server_id pid,
754 const int argc, const char **argv)
756 if (argc != 1) {
757 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
758 return False;
761 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
764 /* Force a SAM synchronisation */
766 static bool do_samsync(struct messaging_context *msg_ctx,
767 const struct server_id pid,
768 const int argc, const char **argv)
770 if (argc != 1) {
771 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
772 return False;
775 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
778 /* Force a SAM replication */
780 static bool do_samrepl(struct messaging_context *msg_ctx,
781 const struct server_id pid,
782 const int argc, const char **argv)
784 if (argc != 1) {
785 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
786 return False;
789 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
792 /* Display talloc pool usage */
794 static bool do_poolusage(struct messaging_context *msg_ctx,
795 const struct server_id pid,
796 const int argc, const char **argv)
798 if (argc != 1) {
799 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
800 return False;
803 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
805 /* Send a message and register our interest in a reply */
807 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
808 return False;
810 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
812 /* No replies were received within the timeout period */
814 if (num_replies == 0)
815 printf("No replies received\n");
817 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
819 return num_replies;
822 /* Perform a dmalloc mark */
824 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
825 const struct server_id pid,
826 const int argc, const char **argv)
828 if (argc != 1) {
829 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
830 return False;
833 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
836 /* Perform a dmalloc changed */
838 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
839 const struct server_id pid,
840 const int argc, const char **argv)
842 if (argc != 1) {
843 fprintf(stderr, "Usage: smbcontrol <dest> "
844 "dmalloc-log-changed\n");
845 return False;
848 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
849 NULL, 0);
852 /* Shutdown a server process */
854 static bool do_shutdown(struct messaging_context *msg_ctx,
855 const struct server_id pid,
856 const int argc, const char **argv)
858 if (argc != 1) {
859 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
860 return False;
863 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
866 /* Notify a driver upgrade */
868 static bool do_drvupgrade(struct messaging_context *msg_ctx,
869 const struct server_id pid,
870 const int argc, const char **argv)
872 if (argc != 2) {
873 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
874 "<driver-name>\n");
875 return False;
878 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
879 strlen(argv[1]) + 1);
882 static bool do_winbind_online(struct messaging_context *msg_ctx,
883 const struct server_id pid,
884 const int argc, const char **argv)
886 TDB_CONTEXT *tdb;
888 if (argc != 1) {
889 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
890 return False;
893 /* Remove the entry in the winbindd_cache tdb to tell a later
894 starting winbindd that we're online. */
896 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
897 if (!tdb) {
898 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
899 cache_path("winbindd_cache.tdb"));
900 return False;
903 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
904 tdb_close(tdb);
906 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
909 static bool do_winbind_offline(struct messaging_context *msg_ctx,
910 const struct server_id pid,
911 const int argc, const char **argv)
913 TDB_CONTEXT *tdb;
914 bool ret = False;
915 int retry = 0;
917 if (argc != 1) {
918 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
919 return False;
922 /* Create an entry in the winbindd_cache tdb to tell a later
923 starting winbindd that we're offline. We may actually create
924 it here... */
926 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
927 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
928 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
929 O_RDWR|O_CREAT, 0600);
931 if (!tdb) {
932 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
933 cache_path("winbindd_cache.tdb"));
934 return False;
937 /* There's a potential race condition that if a child
938 winbindd detects a domain is online at the same time
939 we're trying to tell it to go offline that it might
940 delete the record we add between us adding it and
941 sending the message. Minimize this by retrying up to
942 5 times. */
944 for (retry = 0; retry < 5; retry++) {
945 TDB_DATA d;
946 uint8 buf[4];
948 ZERO_STRUCT(d);
950 SIVAL(buf, 0, time(NULL));
951 d.dptr = buf;
952 d.dsize = 4;
954 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
956 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
957 NULL, 0);
959 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
960 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
962 if (!d.dptr || d.dsize != 4) {
963 SAFE_FREE(d.dptr);
964 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
965 } else {
966 SAFE_FREE(d.dptr);
967 break;
971 tdb_close(tdb);
972 return ret;
975 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
976 const struct server_id pid,
977 const int argc, const char **argv)
979 struct server_id myid;
981 myid = procid_self();
983 if (argc != 1) {
984 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
985 return False;
988 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
989 print_pid_string_cb);
991 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
992 sizeof(myid)))
993 return False;
995 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
997 /* No replies were received within the timeout period */
999 if (num_replies == 0)
1000 printf("No replies received\n");
1002 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1004 return num_replies;
1007 static bool do_dump_event_list(struct messaging_context *msg_ctx,
1008 const struct server_id pid,
1009 const int argc, const char **argv)
1011 struct server_id myid;
1013 myid = procid_self();
1015 if (argc != 1) {
1016 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1017 return False;
1020 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1023 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1024 const struct server_id pid,
1025 const int argc, const char **argv)
1027 const char *domain = NULL;
1028 int domain_len = 0;
1029 struct server_id myid;
1030 uint8_t *buf = NULL;
1031 int buf_len = 0;
1033 myid = procid_self();
1035 if (argc < 1 || argc > 2) {
1036 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1037 "<domain>\n");
1038 return false;
1041 if (argc == 2) {
1042 domain = argv[1];
1043 domain_len = strlen(argv[1]) + 1;
1046 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1047 print_pid_string_cb);
1049 buf_len = sizeof(myid)+domain_len;
1050 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1051 if (!buf) {
1052 return false;
1055 memcpy(buf, &myid, sizeof(myid));
1056 memcpy(&buf[sizeof(myid)], domain, domain_len);
1058 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1059 buf, buf_len))
1061 SAFE_FREE(buf);
1062 return false;
1065 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1067 /* No replies were received within the timeout period */
1069 SAFE_FREE(buf);
1070 if (num_replies == 0) {
1071 printf("No replies received\n");
1074 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1076 return num_replies;
1079 static void winbind_validate_cache_cb(struct messaging_context *msg,
1080 void *private_data,
1081 uint32_t msg_type,
1082 struct server_id pid,
1083 DATA_BLOB *data)
1085 char *src_string = procid_str(NULL, &pid);
1086 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1087 (*(data->data) == 0 ? "" : "NOT "), src_string);
1088 TALLOC_FREE(src_string);
1089 num_replies++;
1092 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1093 const struct server_id pid,
1094 const int argc, const char **argv)
1096 struct server_id myid = procid_self();
1098 if (argc != 1) {
1099 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1100 return False;
1103 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1104 winbind_validate_cache_cb);
1106 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1107 sizeof(myid))) {
1108 return False;
1111 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1113 if (num_replies == 0) {
1114 printf("No replies received\n");
1117 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1119 return num_replies;
1122 static bool do_reload_config(struct messaging_context *msg_ctx,
1123 const struct server_id pid,
1124 const int argc, const char **argv)
1126 if (argc != 1) {
1127 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1128 return False;
1131 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1134 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1136 fstring unix_name;
1137 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1138 fstrcpy(unix_name, name);
1139 strupper_m(unix_name);
1140 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1141 n->name_type = (unsigned int)type & 0xFF;
1142 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1145 static bool do_nodestatus(struct messaging_context *msg_ctx,
1146 const struct server_id pid,
1147 const int argc, const char **argv)
1149 struct packet_struct p;
1151 if (argc != 2) {
1152 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1153 return False;
1156 ZERO_STRUCT(p);
1158 p.ip = interpret_addr2(argv[1]);
1159 p.port = 137;
1160 p.packet_type = NMB_PACKET;
1162 p.packet.nmb.header.name_trn_id = 10;
1163 p.packet.nmb.header.opcode = 0;
1164 p.packet.nmb.header.response = False;
1165 p.packet.nmb.header.nm_flags.bcast = False;
1166 p.packet.nmb.header.nm_flags.recursion_available = False;
1167 p.packet.nmb.header.nm_flags.recursion_desired = False;
1168 p.packet.nmb.header.nm_flags.trunc = False;
1169 p.packet.nmb.header.nm_flags.authoritative = False;
1170 p.packet.nmb.header.rcode = 0;
1171 p.packet.nmb.header.qdcount = 1;
1172 p.packet.nmb.header.ancount = 0;
1173 p.packet.nmb.header.nscount = 0;
1174 p.packet.nmb.header.arcount = 0;
1175 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1176 p.packet.nmb.question.question_type = 0x21;
1177 p.packet.nmb.question.question_class = 0x1;
1179 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1182 /* A list of message type supported */
1184 static const struct {
1185 const char *name; /* Option name */
1186 bool (*fn)(struct messaging_context *msg_ctx,
1187 const struct server_id pid,
1188 const int argc, const char **argv);
1189 const char *help; /* Short help text */
1190 } msg_types[] = {
1191 { "debug", do_debug, "Set debuglevel" },
1192 { "force-election", do_election,
1193 "Force a browse election" },
1194 { "ping", do_ping, "Elicit a response" },
1195 { "profile", do_profile, "" },
1196 { "inject", do_inject_fault,
1197 "Inject a fatal signal into a running smbd"},
1198 { "stacktrace", do_daemon_stack_trace,
1199 "Display a stack trace of a daemon" },
1200 { "profilelevel", do_profilelevel, "" },
1201 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1202 { "printnotify", do_printnotify, "Send a print notify message" },
1203 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1204 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1205 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1206 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1207 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1208 { "samrepl", do_samrepl, "Initiate SAM replication" },
1209 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1210 { "dmalloc-mark", do_dmalloc_mark, "" },
1211 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1212 { "shutdown", do_shutdown, "Shut down daemon" },
1213 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1214 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1215 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1216 { "online", do_winbind_online, "Ask winbind to go into online state"},
1217 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1218 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1219 { "dump-event-list", do_dump_event_list, "Dump event list"},
1220 { "validate-cache" , do_winbind_validate_cache,
1221 "Validate winbind's credential cache" },
1222 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1223 { "noop", do_noop, "Do nothing" },
1224 { NULL }
1227 /* Display usage information */
1229 static void usage(poptContext pc)
1231 int i;
1233 poptPrintHelp(pc, stderr, 0);
1235 fprintf(stderr, "\n");
1236 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1237 "process ID\n");
1239 fprintf(stderr, "\n");
1240 fprintf(stderr, "<message-type> is one of:\n");
1242 for (i = 0; msg_types[i].name; i++)
1243 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1244 msg_types[i].help);
1246 fprintf(stderr, "\n");
1248 exit(1);
1251 /* Return the pid number for a string destination */
1253 static struct server_id parse_dest(const char *dest)
1255 struct server_id result = {-1};
1256 pid_t pid;
1258 /* Zero is a special return value for broadcast to all processes */
1260 if (strequal(dest, "all")) {
1261 return interpret_pid(MSG_BROADCAST_PID_STR);
1264 /* Try self - useful for testing */
1266 if (strequal(dest, "self")) {
1267 return procid_self();
1270 /* Fix winbind typo. */
1271 if (strequal(dest, "winbind")) {
1272 dest = "winbindd";
1275 /* Check for numeric pid number */
1276 result = interpret_pid(dest);
1278 /* Zero isn't valid if not "all". */
1279 if (result.pid && procid_valid(&result)) {
1280 return result;
1283 /* Look up other destinations in pidfile directory */
1285 if ((pid = pidfile_pid(dest)) != 0) {
1286 return pid_to_procid(pid);
1289 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1291 return result;
1294 /* Execute smbcontrol command */
1296 static bool do_command(struct messaging_context *msg_ctx,
1297 int argc, const char **argv)
1299 const char *dest = argv[0], *command = argv[1];
1300 struct server_id pid;
1301 int i;
1303 /* Check destination */
1305 pid = parse_dest(dest);
1306 if (!procid_valid(&pid)) {
1307 return False;
1310 /* Check command */
1312 for (i = 0; msg_types[i].name; i++) {
1313 if (strequal(command, msg_types[i].name))
1314 return msg_types[i].fn(msg_ctx, pid,
1315 argc - 1, argv + 1);
1318 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1320 return False;
1323 static void smbcontrol_help(poptContext pc,
1324 enum poptCallbackReason preason,
1325 struct poptOption * poption,
1326 const char * parg,
1327 void * pdata)
1329 if (poption->shortName != '?') {
1330 poptPrintUsage(pc, stdout, 0);
1331 } else {
1332 usage(pc);
1335 exit(0);
1338 struct poptOption help_options[] = {
1339 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1340 NULL, NULL },
1341 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1342 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1343 { NULL }
1346 /* Main program */
1348 int main(int argc, const char **argv)
1350 poptContext pc;
1351 int opt;
1352 struct tevent_context *evt_ctx;
1353 struct messaging_context *msg_ctx;
1355 static struct poptOption long_options[] = {
1356 /* POPT_AUTOHELP */
1357 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1358 0, "Help options:", NULL },
1359 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1360 "Set timeout value in seconds", "TIMEOUT" },
1362 POPT_COMMON_SAMBA
1363 POPT_TABLEEND
1365 TALLOC_CTX *frame = talloc_stackframe();
1366 int ret = 0;
1368 load_case_tables();
1370 setup_logging(argv[0],True);
1372 /* Parse command line arguments using popt */
1374 pc = poptGetContext(
1375 "smbcontrol", argc, (const char **)argv, long_options, 0);
1377 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1378 "<parameters>");
1380 if (argc == 1)
1381 usage(pc);
1383 while ((opt = poptGetNextOpt(pc)) != -1) {
1384 switch(opt) {
1385 case 't': /* --timeout */
1386 break;
1387 default:
1388 fprintf(stderr, "Invalid option\n");
1389 poptPrintHelp(pc, stderr, 0);
1390 break;
1394 /* We should now have the remaining command line arguments in
1395 argv. The argc parameter should have been decremented to the
1396 correct value in the above switch statement. */
1398 argv = (const char **)poptGetArgs(pc);
1399 argc = 0;
1400 if (argv != NULL) {
1401 while (argv[argc] != NULL) {
1402 argc++;
1406 if (argc <= 1)
1407 usage(pc);
1409 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1411 /* Need to invert sense of return code -- samba
1412 * routines mostly return True==1 for success, but
1413 * shell needs 0. */
1415 if (!(evt_ctx = tevent_context_init(NULL)) ||
1416 !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1417 fprintf(stderr, "could not init messaging context\n");
1418 TALLOC_FREE(frame);
1419 exit(1);
1422 ret = !do_command(msg_ctx, argc, argv);
1423 TALLOC_FREE(frame);
1424 return ret;