s3: Make "smbcontrol xx debuglevel" print the correct cluster pid
[Samba/cd1.git] / source3 / utils / smbcontrol.c
blobe97d5541799f69619c099ac5b56648475fcde171
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"
28 #if HAVE_LIBUNWIND_H
29 #include <libunwind.h>
30 #endif
32 #if HAVE_LIBUNWIND_PTRACE_H
33 #include <libunwind-ptrace.h>
34 #endif
36 #if HAVE_SYS_PTRACE_H
37 #include <sys/ptrace.h>
38 #endif
40 /* Default timeout value when waiting for replies (in seconds) */
42 #define DEFAULT_TIMEOUT 10
44 static int timeout = DEFAULT_TIMEOUT;
45 static int num_replies; /* Used by message callback fns */
47 /* Send a message to a destination pid. Zero means broadcast smbd. */
49 static bool send_message(struct messaging_context *msg_ctx,
50 struct server_id pid, int msg_type,
51 const void *buf, int len)
53 bool ret;
54 int n_sent = 0;
56 if (procid_to_pid(&pid) != 0)
57 return NT_STATUS_IS_OK(
58 messaging_send_buf(msg_ctx, pid, msg_type,
59 (uint8 *)buf, len));
61 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
62 DEBUG(10,("smbcontrol/send_message: broadcast message to "
63 "%d processes\n", n_sent));
65 return ret;
68 static void smbcontrol_timeout(struct tevent_context *event_ctx,
69 struct tevent_timer *te,
70 struct timeval now,
71 void *private_data)
73 bool *timed_out = (bool *)private_data;
74 TALLOC_FREE(te);
75 *timed_out = True;
78 /* Wait for one or more reply messages */
80 static void wait_replies(struct messaging_context *msg_ctx,
81 bool multiple_replies)
83 struct tevent_timer *te;
84 bool timed_out = False;
86 if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
87 timeval_current_ofs(timeout, 0),
88 smbcontrol_timeout, (void *)&timed_out))) {
89 DEBUG(0, ("tevent_add_timer failed\n"));
90 return;
93 while (!timed_out) {
94 int ret;
95 if (num_replies > 0 && !multiple_replies)
96 break;
97 ret = tevent_loop_once(messaging_event_context(msg_ctx));
98 if (ret != 0) {
99 break;
104 /* Message handler callback that displays the PID and a string on stdout */
106 static void print_pid_string_cb(struct messaging_context *msg,
107 void *private_data,
108 uint32_t msg_type,
109 struct server_id pid,
110 DATA_BLOB *data)
112 char *pidstr;
114 pidstr = procid_str(talloc_tos(), &pid);
115 printf("PID %s: %.*s", pidstr, (int)data->length,
116 (const char *)data->data);
117 TALLOC_FREE(pidstr);
118 num_replies++;
121 /* Message handler callback that displays a string on stdout */
123 static void print_string_cb(struct messaging_context *msg,
124 void *private_data,
125 uint32_t msg_type,
126 struct server_id pid,
127 DATA_BLOB *data)
129 printf("%*s", (int)data->length, (const char *)data->data);
130 num_replies++;
133 /* Send no message. Useful for testing. */
135 static bool do_noop(struct messaging_context *msg_ctx,
136 const struct server_id pid,
137 const int argc, const char **argv)
139 if (argc != 1) {
140 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
141 return False;
144 /* Move along, nothing to see here */
146 return True;
149 /* Send a debug string */
151 static bool do_debug(struct messaging_context *msg_ctx,
152 const struct server_id pid,
153 const int argc, const char **argv)
155 if (argc != 2) {
156 fprintf(stderr, "Usage: smbcontrol <dest> debug "
157 "<debug-string>\n");
158 return False;
161 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
162 strlen(argv[1]) + 1);
165 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
167 /* Return the name of a process given it's PID. This will only work on Linux,
168 * but that's probably moot since this whole stack tracing implementatino is
169 * Linux-specific anyway.
171 static const char * procname(pid_t pid, char * buf, size_t bufsz)
173 char path[64];
174 FILE * fp;
176 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
177 (unsigned long long)pid);
178 if ((fp = fopen(path, "r")) == NULL) {
179 return NULL;
182 fgets(buf, bufsz, fp);
184 fclose(fp);
185 return buf;
188 static void print_stack_trace(pid_t pid, int * count)
190 void * pinfo = NULL;
191 unw_addr_space_t aspace = NULL;
192 unw_cursor_t cursor;
193 unw_word_t ip, sp;
195 char nbuf[256];
196 unw_word_t off;
198 int ret;
200 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
201 fprintf(stderr,
202 "Failed to attach to process %llu: %s\n",
203 (unsigned long long)pid, strerror(errno));
204 return;
207 /* Wait until the attach is complete. */
208 waitpid(pid, NULL, 0);
210 if (((pinfo = _UPT_create(pid)) == NULL) ||
211 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
212 /* Probably out of memory. */
213 fprintf(stderr,
214 "Unable to initialize stack unwind for process %llu\n",
215 (unsigned long long)pid);
216 goto cleanup;
219 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
220 fprintf(stderr,
221 "Unable to unwind stack for process %llu: %s\n",
222 (unsigned long long)pid, unw_strerror(ret));
223 goto cleanup;
226 if (*count > 0) {
227 printf("\n");
230 if (procname(pid, nbuf, sizeof(nbuf))) {
231 printf("Stack trace for process %llu (%s):\n",
232 (unsigned long long)pid, nbuf);
233 } else {
234 printf("Stack trace for process %llu:\n",
235 (unsigned long long)pid);
238 while (unw_step(&cursor) > 0) {
239 ip = sp = off = 0;
240 unw_get_reg(&cursor, UNW_REG_IP, &ip);
241 unw_get_reg(&cursor, UNW_REG_SP, &sp);
243 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
244 if (ret != 0 && ret != -UNW_ENOMEM) {
245 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
247 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
248 nbuf, (long long)off, (long long)ip,
249 (long long)sp);
252 (*count)++;
254 cleanup:
255 if (aspace) {
256 unw_destroy_addr_space(aspace);
259 if (pinfo) {
260 _UPT_destroy(pinfo);
263 ptrace(PTRACE_DETACH, pid, NULL, NULL);
266 static int stack_trace_connection(const struct connections_key *key,
267 const struct connections_data *crec,
268 void *priv)
270 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
272 return 0;
275 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
276 const struct server_id pid,
277 const int argc, const char **argv)
279 pid_t dest;
280 int count = 0;
282 if (argc != 1) {
283 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
284 return False;
287 dest = procid_to_pid(&pid);
289 if (dest != 0) {
290 /* It would be nice to be able to make sure that this PID is
291 * the PID of a smbd/winbind/nmbd process, not some random PID
292 * the user liked the look of. It doesn't seem like it's worth
293 * the effort at the moment, however.
295 print_stack_trace(dest, &count);
296 } else {
297 connections_forall_read(stack_trace_connection, &count);
300 return True;
303 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
305 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
306 const struct server_id pid,
307 const int argc, const char **argv)
309 fprintf(stderr,
310 "Daemon stack tracing is not supported on this platform\n");
311 return False;
314 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
316 /* Inject a fault (fatal signal) into a running smbd */
318 static bool do_inject_fault(struct messaging_context *msg_ctx,
319 const struct server_id pid,
320 const int argc, const char **argv)
322 if (argc != 2) {
323 fprintf(stderr, "Usage: smbcontrol <dest> inject "
324 "<bus|hup|term|internal|segv>\n");
325 return False;
328 #ifndef DEVELOPER
329 fprintf(stderr, "Fault injection is only available in "
330 "developer builds\n");
331 return False;
332 #else /* DEVELOPER */
334 int sig = 0;
336 if (strcmp(argv[1], "bus") == 0) {
337 sig = SIGBUS;
338 } else if (strcmp(argv[1], "hup") == 0) {
339 sig = SIGHUP;
340 } else if (strcmp(argv[1], "term") == 0) {
341 sig = SIGTERM;
342 } else if (strcmp(argv[1], "segv") == 0) {
343 sig = SIGSEGV;
344 } else if (strcmp(argv[1], "internal") == 0) {
345 /* Force an internal error, ie. an unclean exit. */
346 sig = -1;
347 } else {
348 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
349 return False;
352 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
353 &sig, sizeof(int));
355 #endif /* DEVELOPER */
358 /* Force a browser election */
360 static bool do_election(struct messaging_context *msg_ctx,
361 const struct server_id pid,
362 const int argc, const char **argv)
364 if (argc != 1) {
365 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
366 return False;
369 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
372 /* Ping a samba daemon process */
374 static void pong_cb(struct messaging_context *msg,
375 void *private_data,
376 uint32_t msg_type,
377 struct server_id pid,
378 DATA_BLOB *data)
380 char *src_string = procid_str(NULL, &pid);
381 printf("PONG from pid %s\n", src_string);
382 TALLOC_FREE(src_string);
383 num_replies++;
386 static bool do_ping(struct messaging_context *msg_ctx,
387 const struct server_id pid,
388 const int argc, const char **argv)
390 if (argc != 1) {
391 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
392 return False;
395 /* Send a message and register our interest in a reply */
397 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
398 return False;
400 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
402 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
404 /* No replies were received within the timeout period */
406 if (num_replies == 0)
407 printf("No replies received\n");
409 messaging_deregister(msg_ctx, MSG_PONG, NULL);
411 return num_replies;
414 /* Set profiling options */
416 static bool do_profile(struct messaging_context *msg_ctx,
417 const struct server_id pid,
418 const int argc, const char **argv)
420 int v;
422 if (argc != 2) {
423 fprintf(stderr, "Usage: smbcontrol <dest> profile "
424 "<off|count|on|flush>\n");
425 return False;
428 if (strcmp(argv[1], "off") == 0) {
429 v = 0;
430 } else if (strcmp(argv[1], "count") == 0) {
431 v = 1;
432 } else if (strcmp(argv[1], "on") == 0) {
433 v = 2;
434 } else if (strcmp(argv[1], "flush") == 0) {
435 v = 3;
436 } else {
437 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
438 return False;
441 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
444 /* Return the profiling level */
446 static void profilelevel_cb(struct messaging_context *msg_ctx,
447 void *private_data,
448 uint32_t msg_type,
449 struct server_id pid,
450 DATA_BLOB *data)
452 int level;
453 const char *s;
455 num_replies++;
457 if (data->length != sizeof(int)) {
458 fprintf(stderr, "invalid message length %ld returned\n",
459 (unsigned long)data->length);
460 return;
463 memcpy(&level, data->data, sizeof(int));
465 switch (level) {
466 case 0:
467 s = "not enabled";
468 break;
469 case 1:
470 s = "off";
471 break;
472 case 3:
473 s = "count only";
474 break;
475 case 7:
476 s = "count and time";
477 break;
478 default:
479 s = "BOGUS";
480 break;
483 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
486 static void profilelevel_rqst(struct messaging_context *msg_ctx,
487 void *private_data,
488 uint32_t msg_type,
489 struct server_id pid,
490 DATA_BLOB *data)
492 int v = 0;
494 /* Send back a dummy reply */
496 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
499 static bool do_profilelevel(struct messaging_context *msg_ctx,
500 const struct server_id pid,
501 const int argc, const char **argv)
503 if (argc != 1) {
504 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
505 return False;
508 /* Send a message and register our interest in a reply */
510 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
511 return False;
513 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
514 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
515 profilelevel_rqst);
517 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
519 /* No replies were received within the timeout period */
521 if (num_replies == 0)
522 printf("No replies received\n");
524 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
526 return num_replies;
529 /* Display debug level settings */
531 static bool do_debuglevel(struct messaging_context *msg_ctx,
532 const struct server_id pid,
533 const int argc, const char **argv)
535 if (argc != 1) {
536 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
537 return False;
540 /* Send a message and register our interest in a reply */
542 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
543 return False;
545 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
547 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
549 /* No replies were received within the timeout period */
551 if (num_replies == 0)
552 printf("No replies received\n");
554 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
556 return num_replies;
559 /* Send a print notify message */
561 static bool do_printnotify(struct messaging_context *msg_ctx,
562 const struct server_id pid,
563 const int argc, const char **argv)
565 const char *cmd;
567 /* Check for subcommand */
569 if (argc == 1) {
570 fprintf(stderr, "Must specify subcommand:\n");
571 fprintf(stderr, "\tqueuepause <printername>\n");
572 fprintf(stderr, "\tqueueresume <printername>\n");
573 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
574 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
575 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
576 fprintf(stderr, "\tprinter <printername> <comment|port|"
577 "driver> <value>\n");
579 return False;
582 cmd = argv[1];
584 if (strcmp(cmd, "queuepause") == 0) {
586 if (argc != 3) {
587 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
588 " queuepause <printername>\n");
589 return False;
592 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
594 goto send;
596 } else if (strcmp(cmd, "queueresume") == 0) {
598 if (argc != 3) {
599 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
600 " queuereume <printername>\n");
601 return False;
604 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
606 goto send;
608 } else if (strcmp(cmd, "jobpause") == 0) {
609 int jobid;
611 if (argc != 4) {
612 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
613 " jobpause <printername> <unix-jobid>\n");
614 return False;
617 jobid = atoi(argv[3]);
619 notify_job_status_byname(
620 argv[2], jobid, JOB_STATUS_PAUSED,
621 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
623 goto send;
625 } else if (strcmp(cmd, "jobresume") == 0) {
626 int jobid;
628 if (argc != 4) {
629 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
630 " jobpause <printername> <unix-jobid>\n");
631 return False;
634 jobid = atoi(argv[3]);
636 notify_job_status_byname(
637 argv[2], jobid, JOB_STATUS_QUEUED,
638 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
640 goto send;
642 } else if (strcmp(cmd, "jobdelete") == 0) {
643 int jobid;
645 if (argc != 4) {
646 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
647 " jobpause <printername> <unix-jobid>\n");
648 return False;
651 jobid = atoi(argv[3]);
653 notify_job_status_byname(
654 argv[2], jobid, JOB_STATUS_DELETING,
655 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
657 notify_job_status_byname(
658 argv[2], jobid, JOB_STATUS_DELETING|
659 JOB_STATUS_DELETED,
660 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
662 goto send;
664 } else if (strcmp(cmd, "printer") == 0) {
665 uint32 attribute;
667 if (argc != 5) {
668 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
669 "printer <printername> <comment|port|driver> "
670 "<value>\n");
671 return False;
674 if (strcmp(argv[3], "comment") == 0) {
675 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
676 } else if (strcmp(argv[3], "port") == 0) {
677 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
678 } else if (strcmp(argv[3], "driver") == 0) {
679 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
680 } else {
681 fprintf(stderr, "Invalid printer command '%s'\n",
682 argv[3]);
683 return False;
686 notify_printer_byname(argv[2], attribute,
687 CONST_DISCARD(char *, argv[4]));
689 goto send;
692 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
693 return False;
695 send:
696 print_notify_send_messages(msg_ctx, 0);
697 return True;
700 /* Close a share */
702 static bool do_closeshare(struct messaging_context *msg_ctx,
703 const struct server_id pid,
704 const int argc, const char **argv)
706 if (argc != 2) {
707 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
708 "<sharename>\n");
709 return False;
712 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
713 strlen(argv[1]) + 1);
716 /* force a blocking lock retry */
718 static bool do_lockretry(struct messaging_context *msg_ctx,
719 const struct server_id pid,
720 const int argc, const char **argv)
722 if (argc != 1) {
723 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
724 return False;
727 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
730 /* force a validation of all brl entries, including re-sends. */
732 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
733 const struct server_id pid,
734 const int argc, const char **argv)
736 if (argc != 1) {
737 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
738 return False;
741 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
744 /* Force a SAM synchronisation */
746 static bool do_samsync(struct messaging_context *msg_ctx,
747 const struct server_id pid,
748 const int argc, const char **argv)
750 if (argc != 1) {
751 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
752 return False;
755 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
758 /* Force a SAM replication */
760 static bool do_samrepl(struct messaging_context *msg_ctx,
761 const struct server_id pid,
762 const int argc, const char **argv)
764 if (argc != 1) {
765 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
766 return False;
769 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
772 /* Display talloc pool usage */
774 static bool do_poolusage(struct messaging_context *msg_ctx,
775 const struct server_id pid,
776 const int argc, const char **argv)
778 if (argc != 1) {
779 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
780 return False;
783 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
785 /* Send a message and register our interest in a reply */
787 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
788 return False;
790 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
792 /* No replies were received within the timeout period */
794 if (num_replies == 0)
795 printf("No replies received\n");
797 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
799 return num_replies;
802 /* Perform a dmalloc mark */
804 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
805 const struct server_id pid,
806 const int argc, const char **argv)
808 if (argc != 1) {
809 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
810 return False;
813 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
816 /* Perform a dmalloc changed */
818 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
819 const struct server_id pid,
820 const int argc, const char **argv)
822 if (argc != 1) {
823 fprintf(stderr, "Usage: smbcontrol <dest> "
824 "dmalloc-log-changed\n");
825 return False;
828 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
829 NULL, 0);
832 /* Shutdown a server process */
834 static bool do_shutdown(struct messaging_context *msg_ctx,
835 const struct server_id pid,
836 const int argc, const char **argv)
838 if (argc != 1) {
839 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
840 return False;
843 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
846 /* Notify a driver upgrade */
848 static bool do_drvupgrade(struct messaging_context *msg_ctx,
849 const struct server_id pid,
850 const int argc, const char **argv)
852 if (argc != 2) {
853 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
854 "<driver-name>\n");
855 return False;
858 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
859 strlen(argv[1]) + 1);
862 static bool do_winbind_online(struct messaging_context *msg_ctx,
863 const struct server_id pid,
864 const int argc, const char **argv)
866 TDB_CONTEXT *tdb;
868 if (argc != 1) {
869 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
870 return False;
873 /* Remove the entry in the winbindd_cache tdb to tell a later
874 starting winbindd that we're online. */
876 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
877 if (!tdb) {
878 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
879 cache_path("winbindd_cache.tdb"));
880 return False;
883 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
884 tdb_close(tdb);
886 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
889 static bool do_winbind_offline(struct messaging_context *msg_ctx,
890 const struct server_id pid,
891 const int argc, const char **argv)
893 TDB_CONTEXT *tdb;
894 bool ret = False;
895 int retry = 0;
897 if (argc != 1) {
898 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
899 return False;
902 /* Create an entry in the winbindd_cache tdb to tell a later
903 starting winbindd that we're offline. We may actually create
904 it here... */
906 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
907 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
908 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
910 if (!tdb) {
911 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
912 cache_path("winbindd_cache.tdb"));
913 return False;
916 /* There's a potential race condition that if a child
917 winbindd detects a domain is online at the same time
918 we're trying to tell it to go offline that it might
919 delete the record we add between us adding it and
920 sending the message. Minimize this by retrying up to
921 5 times. */
923 for (retry = 0; retry < 5; retry++) {
924 TDB_DATA d;
925 uint8 buf[4];
927 ZERO_STRUCT(d);
929 SIVAL(buf, 0, time(NULL));
930 d.dptr = buf;
931 d.dsize = 4;
933 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
935 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
936 NULL, 0);
938 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
939 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
941 if (!d.dptr || d.dsize != 4) {
942 SAFE_FREE(d.dptr);
943 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
944 } else {
945 SAFE_FREE(d.dptr);
946 break;
950 tdb_close(tdb);
951 return ret;
954 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
955 const struct server_id pid,
956 const int argc, const char **argv)
958 struct server_id myid;
960 myid = procid_self();
962 if (argc != 1) {
963 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
964 return False;
967 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
968 print_pid_string_cb);
970 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
971 sizeof(myid)))
972 return False;
974 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
976 /* No replies were received within the timeout period */
978 if (num_replies == 0)
979 printf("No replies received\n");
981 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
983 return num_replies;
986 static bool do_dump_event_list(struct messaging_context *msg_ctx,
987 const struct server_id pid,
988 const int argc, const char **argv)
990 struct server_id myid;
992 myid = procid_self();
994 if (argc != 1) {
995 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
996 return False;
999 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1002 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1003 const struct server_id pid,
1004 const int argc, const char **argv)
1006 const char *domain = NULL;
1007 int domain_len = 0;
1008 struct server_id myid;
1009 uint8_t *buf = NULL;
1010 int buf_len = 0;
1012 myid = procid_self();
1014 if (argc < 1 || argc > 2) {
1015 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1016 "<domain>\n");
1017 return false;
1020 if (argc == 2) {
1021 domain = argv[1];
1022 domain_len = strlen(argv[1]) + 1;
1025 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1026 print_pid_string_cb);
1028 buf_len = sizeof(myid)+domain_len;
1029 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1030 if (!buf) {
1031 return false;
1034 memcpy(buf, &myid, sizeof(myid));
1035 memcpy(&buf[sizeof(myid)], domain, domain_len);
1037 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1038 buf, buf_len))
1040 SAFE_FREE(buf);
1041 return false;
1044 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1046 /* No replies were received within the timeout period */
1048 SAFE_FREE(buf);
1049 if (num_replies == 0) {
1050 printf("No replies received\n");
1053 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1055 return num_replies;
1058 static void winbind_validate_cache_cb(struct messaging_context *msg,
1059 void *private_data,
1060 uint32_t msg_type,
1061 struct server_id pid,
1062 DATA_BLOB *data)
1064 char *src_string = procid_str(NULL, &pid);
1065 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1066 (*(data->data) == 0 ? "" : "NOT "), src_string);
1067 TALLOC_FREE(src_string);
1068 num_replies++;
1071 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1072 const struct server_id pid,
1073 const int argc, const char **argv)
1075 struct server_id myid = procid_self();
1077 if (argc != 1) {
1078 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1079 return False;
1082 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1083 winbind_validate_cache_cb);
1085 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1086 sizeof(myid))) {
1087 return False;
1090 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1092 if (num_replies == 0) {
1093 printf("No replies received\n");
1096 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1098 return num_replies;
1101 static bool do_reload_config(struct messaging_context *msg_ctx,
1102 const struct server_id pid,
1103 const int argc, const char **argv)
1105 if (argc != 1) {
1106 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1107 return False;
1110 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1113 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1115 fstring unix_name;
1116 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1117 fstrcpy(unix_name, name);
1118 strupper_m(unix_name);
1119 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1120 n->name_type = (unsigned int)type & 0xFF;
1121 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1124 static bool do_nodestatus(struct messaging_context *msg_ctx,
1125 const struct server_id pid,
1126 const int argc, const char **argv)
1128 struct packet_struct p;
1130 if (argc != 2) {
1131 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1132 return False;
1135 ZERO_STRUCT(p);
1137 p.ip = interpret_addr2(argv[1]);
1138 p.port = 137;
1139 p.packet_type = NMB_PACKET;
1141 p.packet.nmb.header.name_trn_id = 10;
1142 p.packet.nmb.header.opcode = 0;
1143 p.packet.nmb.header.response = False;
1144 p.packet.nmb.header.nm_flags.bcast = False;
1145 p.packet.nmb.header.nm_flags.recursion_available = False;
1146 p.packet.nmb.header.nm_flags.recursion_desired = False;
1147 p.packet.nmb.header.nm_flags.trunc = False;
1148 p.packet.nmb.header.nm_flags.authoritative = False;
1149 p.packet.nmb.header.rcode = 0;
1150 p.packet.nmb.header.qdcount = 1;
1151 p.packet.nmb.header.ancount = 0;
1152 p.packet.nmb.header.nscount = 0;
1153 p.packet.nmb.header.arcount = 0;
1154 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1155 p.packet.nmb.question.question_type = 0x21;
1156 p.packet.nmb.question.question_class = 0x1;
1158 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1161 /* A list of message type supported */
1163 static const struct {
1164 const char *name; /* Option name */
1165 bool (*fn)(struct messaging_context *msg_ctx,
1166 const struct server_id pid,
1167 const int argc, const char **argv);
1168 const char *help; /* Short help text */
1169 } msg_types[] = {
1170 { "debug", do_debug, "Set debuglevel" },
1171 { "force-election", do_election,
1172 "Force a browse election" },
1173 { "ping", do_ping, "Elicit a response" },
1174 { "profile", do_profile, "" },
1175 { "inject", do_inject_fault,
1176 "Inject a fatal signal into a running smbd"},
1177 { "stacktrace", do_daemon_stack_trace,
1178 "Display a stack trace of a daemon" },
1179 { "profilelevel", do_profilelevel, "" },
1180 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1181 { "printnotify", do_printnotify, "Send a print notify message" },
1182 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1183 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1184 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1185 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1186 { "samrepl", do_samrepl, "Initiate SAM replication" },
1187 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1188 { "dmalloc-mark", do_dmalloc_mark, "" },
1189 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1190 { "shutdown", do_shutdown, "Shut down daemon" },
1191 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1192 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1193 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1194 { "online", do_winbind_online, "Ask winbind to go into online state"},
1195 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1196 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1197 { "dump-event-list", do_dump_event_list, "Dump event list"},
1198 { "validate-cache" , do_winbind_validate_cache,
1199 "Validate winbind's credential cache" },
1200 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1201 { "noop", do_noop, "Do nothing" },
1202 { NULL }
1205 /* Display usage information */
1207 static void usage(poptContext pc)
1209 int i;
1211 poptPrintHelp(pc, stderr, 0);
1213 fprintf(stderr, "\n");
1214 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1215 "process ID\n");
1217 fprintf(stderr, "\n");
1218 fprintf(stderr, "<message-type> is one of:\n");
1220 for (i = 0; msg_types[i].name; i++)
1221 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1222 msg_types[i].help);
1224 fprintf(stderr, "\n");
1226 exit(1);
1229 /* Return the pid number for a string destination */
1231 static struct server_id parse_dest(const char *dest)
1233 struct server_id result = {-1};
1234 pid_t pid;
1236 /* Zero is a special return value for broadcast to all processes */
1238 if (strequal(dest, "all")) {
1239 return interpret_pid(MSG_BROADCAST_PID_STR);
1242 /* Try self - useful for testing */
1244 if (strequal(dest, "self")) {
1245 return procid_self();
1248 /* Fix winbind typo. */
1249 if (strequal(dest, "winbind")) {
1250 dest = "winbindd";
1253 /* Check for numeric pid number */
1254 result = interpret_pid(dest);
1256 /* Zero isn't valid if not "all". */
1257 if (result.pid && procid_valid(&result)) {
1258 return result;
1261 /* Look up other destinations in pidfile directory */
1263 if ((pid = pidfile_pid(dest)) != 0) {
1264 return pid_to_procid(pid);
1267 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1269 return result;
1272 /* Execute smbcontrol command */
1274 static bool do_command(struct messaging_context *msg_ctx,
1275 int argc, const char **argv)
1277 const char *dest = argv[0], *command = argv[1];
1278 struct server_id pid;
1279 int i;
1281 /* Check destination */
1283 pid = parse_dest(dest);
1284 if (!procid_valid(&pid)) {
1285 return False;
1288 /* Check command */
1290 for (i = 0; msg_types[i].name; i++) {
1291 if (strequal(command, msg_types[i].name))
1292 return msg_types[i].fn(msg_ctx, pid,
1293 argc - 1, argv + 1);
1296 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1298 return False;
1301 static void smbcontrol_help(poptContext pc,
1302 enum poptCallbackReason preason,
1303 struct poptOption * poption,
1304 const char * parg,
1305 void * pdata)
1307 if (poption->shortName != '?') {
1308 poptPrintUsage(pc, stdout, 0);
1309 } else {
1310 usage(pc);
1313 exit(0);
1316 struct poptOption help_options[] = {
1317 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1318 NULL, NULL },
1319 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1320 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1321 { NULL }
1324 /* Main program */
1326 int main(int argc, const char **argv)
1328 poptContext pc;
1329 int opt;
1330 struct tevent_context *evt_ctx;
1331 struct messaging_context *msg_ctx;
1333 static struct poptOption long_options[] = {
1334 /* POPT_AUTOHELP */
1335 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1336 0, "Help options:", NULL },
1337 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1338 "Set timeout value in seconds", "TIMEOUT" },
1340 POPT_COMMON_SAMBA
1341 POPT_TABLEEND
1343 TALLOC_CTX *frame = talloc_stackframe();
1344 int ret = 0;
1346 load_case_tables();
1348 setup_logging(argv[0],True);
1350 /* Parse command line arguments using popt */
1352 pc = poptGetContext(
1353 "smbcontrol", argc, (const char **)argv, long_options, 0);
1355 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1356 "<parameters>");
1358 if (argc == 1)
1359 usage(pc);
1361 while ((opt = poptGetNextOpt(pc)) != -1) {
1362 switch(opt) {
1363 case 't': /* --timeout */
1364 break;
1365 default:
1366 fprintf(stderr, "Invalid option\n");
1367 poptPrintHelp(pc, stderr, 0);
1368 break;
1372 /* We should now have the remaining command line arguments in
1373 argv. The argc parameter should have been decremented to the
1374 correct value in the above switch statement. */
1376 argv = (const char **)poptGetArgs(pc);
1377 argc = 0;
1378 if (argv != NULL) {
1379 while (argv[argc] != NULL) {
1380 argc++;
1384 if (argc <= 1)
1385 usage(pc);
1387 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1389 /* Need to invert sense of return code -- samba
1390 * routines mostly return True==1 for success, but
1391 * shell needs 0. */
1393 if (!(evt_ctx = tevent_context_init(NULL)) ||
1394 !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1395 fprintf(stderr, "could not init messaging context\n");
1396 TALLOC_FREE(frame);
1397 exit(1);
1400 ret = !do_command(msg_ctx, argc, argv);
1401 TALLOC_FREE(frame);
1402 return ret;