r25239: fix cut-n-paste bug in code with LIBUNWIND support
[Samba/ekacnet.git] / source3 / utils / smbcontrol.c
blob79ab69918ffd40677e88ed8bef29b46e58f7e6c3
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 timeout_handler(struct event_context *event_ctx,
69 struct timed_event *te,
70 const 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 timed_event *te;
84 BOOL timed_out = False;
86 if (!(te = event_add_timed(messaging_event_context(msg_ctx), NULL,
87 timeval_current_ofs(timeout, 0),
88 "smbcontrol_timeout",
89 timeout_handler, (void *)&timed_out))) {
90 DEBUG(0, ("event_add_timed failed\n"));
91 return;
94 while (!timed_out) {
95 message_dispatch(msg_ctx);
96 if (num_replies > 0 && !multiple_replies)
97 break;
98 event_loop_once(messaging_event_context(msg_ctx));
102 /* Message handler callback that displays the PID and a string on stdout */
104 static void print_pid_string_cb(struct messaging_context *msg,
105 void *private_data,
106 uint32_t msg_type,
107 struct server_id pid,
108 DATA_BLOB *data)
110 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
111 (int)data->length, (const char *)data->data);
112 num_replies++;
115 /* Message handler callback that displays a string on stdout */
117 static void print_string_cb(struct messaging_context *msg,
118 void *private_data,
119 uint32_t msg_type,
120 struct server_id pid,
121 DATA_BLOB *data)
123 printf("%.*s", (int)data->length, (const char *)data->data);
124 num_replies++;
127 /* Send no message. Useful for testing. */
129 static BOOL do_noop(struct messaging_context *msg_ctx,
130 const struct server_id pid,
131 const int argc, const char **argv)
133 if (argc != 1) {
134 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
135 return False;
138 /* Move along, nothing to see here */
140 return True;
143 /* Send a debug string */
145 static BOOL do_debug(struct messaging_context *msg_ctx,
146 const struct server_id pid,
147 const int argc, const char **argv)
149 if (argc != 2) {
150 fprintf(stderr, "Usage: smbcontrol <dest> debug "
151 "<debug-string>\n");
152 return False;
155 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
156 strlen(argv[1]) + 1);
159 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
161 /* Return the name of a process given it's PID. This will only work on Linux,
162 * but that's probably moot since this whole stack tracing implementatino is
163 * Linux-specific anyway.
165 static const char * procname(pid_t pid, char * buf, size_t bufsz)
167 char path[64];
168 FILE * fp;
170 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
171 (unsigned long long)pid);
172 if ((fp = fopen(path, "r")) == NULL) {
173 return NULL;
176 fgets(buf, bufsz, fp);
178 fclose(fp);
179 return buf;
182 static void print_stack_trace(pid_t pid, int * count)
184 void * pinfo = NULL;
185 unw_addr_space_t aspace = NULL;
186 unw_cursor_t cursor;
187 unw_word_t ip, sp;
189 char nbuf[256];
190 unw_word_t off;
192 int ret;
194 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
195 fprintf(stderr,
196 "Failed to attach to process %llu: %s\n",
197 (unsigned long long)pid, strerror(errno));
198 return;
201 /* Wait until the attach is complete. */
202 waitpid(pid, NULL, 0);
204 if (((pinfo = _UPT_create(pid)) == NULL) ||
205 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
206 /* Probably out of memory. */
207 fprintf(stderr,
208 "Unable to initialize stack unwind for process %llu\n",
209 (unsigned long long)pid);
210 goto cleanup;
213 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
214 fprintf(stderr,
215 "Unable to unwind stack for process %llu: %s\n",
216 (unsigned long long)pid, unw_strerror(ret));
217 goto cleanup;
220 if (*count > 0) {
221 printf("\n");
224 if (procname(pid, nbuf, sizeof(nbuf))) {
225 printf("Stack trace for process %llu (%s):\n",
226 (unsigned long long)pid, nbuf);
227 } else {
228 printf("Stack trace for process %llu:\n",
229 (unsigned long long)pid);
232 while (unw_step(&cursor) > 0) {
233 ip = sp = off = 0;
234 unw_get_reg(&cursor, UNW_REG_IP, &ip);
235 unw_get_reg(&cursor, UNW_REG_SP, &sp);
237 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
238 if (ret != 0 && ret != -UNW_ENOMEM) {
239 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
241 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
242 nbuf, (long long)off, (long long)ip,
243 (long long)sp);
246 (*count)++;
248 cleanup:
249 if (aspace) {
250 unw_destroy_addr_space(aspace);
253 if (pinfo) {
254 _UPT_destroy(pinfo);
257 ptrace(PTRACE_DETACH, pid, NULL, NULL);
260 static int stack_trace_connection(struct db_record *rec,
261 const struct connections_key *key,
262 const struct connections_data *crec,
263 void *priv)
265 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
267 return 0;
270 static BOOL do_daemon_stack_trace(struct messaging_context *msg_ctx,
271 const struct server_id pid,
272 const int argc, const char **argv)
274 pid_t dest;
275 int count = 0;
277 if (argc != 1) {
278 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
279 return False;
282 dest = procid_to_pid(&pid);
284 if (dest != 0) {
285 /* It would be nice to be able to make sure that this PID is
286 * the PID of a smbd/winbind/nmbd process, not some random PID
287 * the user liked the look of. It doesn't seem like it's worth
288 * the effort at the moment, however.
290 print_stack_trace(dest, &count);
291 } else {
292 connections_forall(stack_trace_connection, &count);
295 return True;
298 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
300 static BOOL do_daemon_stack_trace(struct messaging_context *msg_ctx,
301 const struct server_id pid,
302 const int argc, const char **argv)
304 fprintf(stderr,
305 "Daemon stack tracing is not supported on this platform\n");
306 return False;
309 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
311 /* Inject a fault (fatal signal) into a running smbd */
313 static BOOL do_inject_fault(struct messaging_context *msg_ctx,
314 const struct server_id pid,
315 const int argc, const char **argv)
317 if (argc != 2) {
318 fprintf(stderr, "Usage: smbcontrol <dest> inject "
319 "<bus|hup|term|internal|segv>\n");
320 return False;
323 #ifndef DEVELOPER
324 fprintf(stderr, "Fault injection is only available in "
325 "developer builds\n");
326 return False;
327 #else /* DEVELOPER */
329 int sig = 0;
331 if (strcmp(argv[1], "bus") == 0) {
332 sig = SIGBUS;
333 } else if (strcmp(argv[1], "hup") == 0) {
334 sig = SIGHUP;
335 } else if (strcmp(argv[1], "term") == 0) {
336 sig = SIGTERM;
337 } else if (strcmp(argv[1], "segv") == 0) {
338 sig = SIGSEGV;
339 } else if (strcmp(argv[1], "internal") == 0) {
340 /* Force an internal error, ie. an unclean exit. */
341 sig = -1;
342 } else {
343 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
344 return False;
347 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
348 &sig, sizeof(int));
350 #endif /* DEVELOPER */
353 /* Force a browser election */
355 static BOOL do_election(struct messaging_context *msg_ctx,
356 const struct server_id pid,
357 const int argc, const char **argv)
359 if (argc != 1) {
360 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
361 return False;
364 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
367 /* Ping a samba daemon process */
369 static void pong_cb(struct messaging_context *msg,
370 void *private_data,
371 uint32_t msg_type,
372 struct server_id pid,
373 DATA_BLOB *data)
375 char *src_string = procid_str(NULL, &pid);
376 printf("PONG from pid %s\n", src_string);
377 TALLOC_FREE(src_string);
378 num_replies++;
381 static BOOL do_ping(struct messaging_context *msg_ctx,
382 const struct server_id pid,
383 const int argc, const char **argv)
385 if (argc != 1) {
386 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
387 return False;
390 /* Send a message and register our interest in a reply */
392 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
393 return False;
395 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
397 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
399 /* No replies were received within the timeout period */
401 if (num_replies == 0)
402 printf("No replies received\n");
404 messaging_deregister(msg_ctx, MSG_PONG, NULL);
406 return num_replies;
409 /* Set profiling options */
411 static BOOL do_profile(struct messaging_context *msg_ctx,
412 const struct server_id pid,
413 const int argc, const char **argv)
415 int v;
417 if (argc != 2) {
418 fprintf(stderr, "Usage: smbcontrol <dest> profile "
419 "<off|count|on|flush>\n");
420 return False;
423 if (strcmp(argv[1], "off") == 0) {
424 v = 0;
425 } else if (strcmp(argv[1], "count") == 0) {
426 v = 1;
427 } else if (strcmp(argv[1], "on") == 0) {
428 v = 2;
429 } else if (strcmp(argv[1], "flush") == 0) {
430 v = 3;
431 } else {
432 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
433 return False;
436 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
439 /* Return the profiling level */
441 static void profilelevel_cb(struct messaging_context *msg_ctx,
442 void *private_data,
443 uint32_t msg_type,
444 struct server_id pid,
445 DATA_BLOB *data)
447 int level;
448 const char *s;
450 num_replies++;
452 if (data->length != sizeof(int)) {
453 fprintf(stderr, "invalid message length %ld returned\n",
454 (unsigned long)data->length);
455 return;
458 memcpy(&level, data->data, sizeof(int));
460 switch (level) {
461 case 0:
462 s = "not enabled";
463 break;
464 case 1:
465 s = "off";
466 break;
467 case 3:
468 s = "count only";
469 break;
470 case 7:
471 s = "count and time";
472 break;
473 default:
474 s = "BOGUS";
475 break;
478 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
481 static void profilelevel_rqst(struct messaging_context *msg_ctx,
482 void *private_data,
483 uint32_t msg_type,
484 struct server_id pid,
485 DATA_BLOB *data)
487 int v = 0;
489 /* Send back a dummy reply */
491 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
494 static BOOL do_profilelevel(struct messaging_context *msg_ctx,
495 const struct server_id pid,
496 const int argc, const char **argv)
498 if (argc != 1) {
499 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
500 return False;
503 /* Send a message and register our interest in a reply */
505 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
506 return False;
508 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
509 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
510 profilelevel_rqst);
512 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
514 /* No replies were received within the timeout period */
516 if (num_replies == 0)
517 printf("No replies received\n");
519 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
521 return num_replies;
524 /* Display debug level settings */
526 static BOOL do_debuglevel(struct messaging_context *msg_ctx,
527 const struct server_id pid,
528 const int argc, const char **argv)
530 if (argc != 1) {
531 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
532 return False;
535 /* Send a message and register our interest in a reply */
537 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
538 return False;
540 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
542 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
544 /* No replies were received within the timeout period */
546 if (num_replies == 0)
547 printf("No replies received\n");
549 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
551 return num_replies;
554 /* Send a print notify message */
556 static BOOL do_printnotify(struct messaging_context *msg_ctx,
557 const struct server_id pid,
558 const int argc, const char **argv)
560 const char *cmd;
562 /* Check for subcommand */
564 if (argc == 1) {
565 fprintf(stderr, "Must specify subcommand:\n");
566 fprintf(stderr, "\tqueuepause <printername>\n");
567 fprintf(stderr, "\tqueueresume <printername>\n");
568 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
569 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
570 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
571 fprintf(stderr, "\tprinter <printername> <comment|port|"
572 "driver> <value>\n");
574 return False;
577 cmd = argv[1];
579 if (strcmp(cmd, "queuepause") == 0) {
581 if (argc != 3) {
582 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
583 " queuepause <printername>\n");
584 return False;
587 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
589 goto send;
591 } else if (strcmp(cmd, "queueresume") == 0) {
593 if (argc != 3) {
594 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
595 " queuereume <printername>\n");
596 return False;
599 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
601 goto send;
603 } else if (strcmp(cmd, "jobpause") == 0) {
604 int jobid;
606 if (argc != 4) {
607 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
608 " jobpause <printername> <unix-jobid>\n");
609 return False;
612 jobid = atoi(argv[3]);
614 notify_job_status_byname(
615 argv[2], jobid, JOB_STATUS_PAUSED,
616 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
618 goto send;
620 } else if (strcmp(cmd, "jobresume") == 0) {
621 int jobid;
623 if (argc != 4) {
624 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
625 " jobpause <printername> <unix-jobid>\n");
626 return False;
629 jobid = atoi(argv[3]);
631 notify_job_status_byname(
632 argv[2], jobid, JOB_STATUS_QUEUED,
633 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
635 goto send;
637 } else if (strcmp(cmd, "jobdelete") == 0) {
638 int jobid;
640 if (argc != 4) {
641 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
642 " jobpause <printername> <unix-jobid>\n");
643 return False;
646 jobid = atoi(argv[3]);
648 notify_job_status_byname(
649 argv[2], jobid, JOB_STATUS_DELETING,
650 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
652 notify_job_status_byname(
653 argv[2], jobid, JOB_STATUS_DELETING|
654 JOB_STATUS_DELETED,
655 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
657 goto send;
659 } else if (strcmp(cmd, "printer") == 0) {
660 uint32 attribute;
662 if (argc != 5) {
663 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
664 "printer <printername> <comment|port|driver> "
665 "<value>\n");
666 return False;
669 if (strcmp(argv[3], "comment") == 0) {
670 attribute = PRINTER_NOTIFY_COMMENT;
671 } else if (strcmp(argv[3], "port") == 0) {
672 attribute = PRINTER_NOTIFY_PORT_NAME;
673 } else if (strcmp(argv[3], "driver") == 0) {
674 attribute = PRINTER_NOTIFY_DRIVER_NAME;
675 } else {
676 fprintf(stderr, "Invalid printer command '%s'\n",
677 argv[3]);
678 return False;
681 notify_printer_byname(argv[2], attribute,
682 CONST_DISCARD(char *, argv[4]));
684 goto send;
687 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
688 return False;
690 send:
691 print_notify_send_messages(msg_ctx, 0);
692 return True;
695 /* Close a share */
697 static BOOL do_closeshare(struct messaging_context *msg_ctx,
698 const struct server_id pid,
699 const int argc, const char **argv)
701 if (argc != 2) {
702 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
703 "<sharename>\n");
704 return False;
707 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
708 strlen(argv[1]) + 1);
711 /* force a blocking lock retry */
713 static BOOL do_lockretry(struct messaging_context *msg_ctx,
714 const struct server_id pid,
715 const int argc, const char **argv)
717 if (argc != 1) {
718 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
719 return False;
722 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
725 /* force a validation of all brl entries, including re-sends. */
727 static BOOL do_brl_revalidate(struct messaging_context *msg_ctx,
728 const struct server_id pid,
729 const int argc, const char **argv)
731 if (argc != 1) {
732 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
733 return False;
736 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
739 /* Force a SAM synchronisation */
741 static BOOL do_samsync(struct messaging_context *msg_ctx,
742 const struct server_id pid,
743 const int argc, const char **argv)
745 if (argc != 1) {
746 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
747 return False;
750 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
753 /* Force a SAM replication */
755 static BOOL do_samrepl(struct messaging_context *msg_ctx,
756 const struct server_id pid,
757 const int argc, const char **argv)
759 if (argc != 1) {
760 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
761 return False;
764 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
767 /* Display talloc pool usage */
769 static BOOL do_poolusage(struct messaging_context *msg_ctx,
770 const struct server_id pid,
771 const int argc, const char **argv)
773 if (argc != 1) {
774 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
775 return False;
778 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
780 /* Send a message and register our interest in a reply */
782 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
783 return False;
785 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
787 /* No replies were received within the timeout period */
789 if (num_replies == 0)
790 printf("No replies received\n");
792 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
794 return num_replies;
797 /* Perform a dmalloc mark */
799 static BOOL do_dmalloc_mark(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> dmalloc-mark\n");
805 return False;
808 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
811 /* Perform a dmalloc changed */
813 static BOOL do_dmalloc_changed(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> "
819 "dmalloc-log-changed\n");
820 return False;
823 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
824 NULL, 0);
827 /* Shutdown a server process */
829 static BOOL do_shutdown(struct messaging_context *msg_ctx,
830 const struct server_id pid,
831 const int argc, const char **argv)
833 if (argc != 1) {
834 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
835 return False;
838 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
841 /* Notify a driver upgrade */
843 static BOOL do_drvupgrade(struct messaging_context *msg_ctx,
844 const struct server_id pid,
845 const int argc, const char **argv)
847 if (argc != 2) {
848 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
849 "<driver-name>\n");
850 return False;
853 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
854 strlen(argv[1]) + 1);
857 static BOOL do_winbind_online(struct messaging_context *msg_ctx,
858 const struct server_id pid,
859 const int argc, const char **argv)
861 TDB_CONTEXT *tdb;
863 if (argc != 1) {
864 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
865 return False;
868 if (!lp_winbind_offline_logon()) {
869 fprintf(stderr, "The parameter \"winbind offline logon\" must "
870 "be set in the [global] section of smb.conf for this "
871 "command to be allowed.\n");
872 return False;
875 /* Remove the entry in the winbindd_cache tdb to tell a later
876 starting winbindd that we're online. */
878 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
879 if (!tdb) {
880 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
881 lock_path("winbindd_cache.tdb"));
882 return False;
885 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
886 tdb_close(tdb);
888 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
891 static BOOL do_winbind_offline(struct messaging_context *msg_ctx,
892 const struct server_id pid,
893 const int argc, const char **argv)
895 TDB_CONTEXT *tdb;
896 BOOL ret = False;
897 int retry = 0;
899 if (argc != 1) {
900 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
901 return False;
904 if (!lp_winbind_offline_logon()) {
905 fprintf(stderr, "The parameter \"winbind offline logon\" must "
906 "be set in the [global] section of smb.conf for this "
907 "command to be allowed.\n");
908 return False;
911 /* Create an entry in the winbindd_cache tdb to tell a later
912 starting winbindd that we're offline. We may actually create
913 it here... */
915 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
916 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
917 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
919 if (!tdb) {
920 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
921 lock_path("winbindd_cache.tdb"));
922 return False;
925 /* There's a potential race condition that if a child
926 winbindd detects a domain is online at the same time
927 we're trying to tell it to go offline that it might
928 delete the record we add between us adding it and
929 sending the message. Minimize this by retrying up to
930 5 times. */
932 for (retry = 0; retry < 5; retry++) {
933 TDB_DATA d;
934 uint8 buf[4];
936 ZERO_STRUCT(d);
938 SIVAL(buf, 0, time(NULL));
939 d.dptr = buf;
940 d.dsize = 4;
942 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
944 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
945 NULL, 0);
947 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
948 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
950 if (!d.dptr || d.dsize != 4) {
951 SAFE_FREE(d.dptr);
952 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
953 } else {
954 SAFE_FREE(d.dptr);
955 break;
959 tdb_close(tdb);
960 return ret;
963 static BOOL do_winbind_onlinestatus(struct messaging_context *msg_ctx,
964 const struct server_id pid,
965 const int argc, const char **argv)
967 struct server_id myid;
969 myid = pid_to_procid(sys_getpid());
971 if (argc != 1) {
972 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
973 return False;
976 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
977 print_pid_string_cb);
979 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
980 sizeof(myid)))
981 return False;
983 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
985 /* No replies were received within the timeout period */
987 if (num_replies == 0)
988 printf("No replies received\n");
990 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
992 return num_replies;
995 static BOOL do_dump_event_list(struct messaging_context *msg_ctx,
996 const struct server_id pid,
997 const int argc, const char **argv)
999 struct server_id myid;
1001 myid = pid_to_procid(sys_getpid());
1003 if (argc != 1) {
1004 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1005 return False;
1008 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1011 static void winbind_validate_cache_cb(struct messaging_context *msg,
1012 void *private_data,
1013 uint32_t msg_type,
1014 struct server_id pid,
1015 DATA_BLOB *data)
1017 char *src_string = procid_str(NULL, &pid);
1018 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1019 (*(data->data) == 0 ? "" : "NOT "), src_string);
1020 TALLOC_FREE(src_string);
1021 num_replies++;
1024 static BOOL do_winbind_validate_cache(struct messaging_context *msg_ctx,
1025 const struct server_id pid,
1026 const int argc, const char **argv)
1028 struct server_id myid = pid_to_procid(sys_getpid());
1030 if (argc != 1) {
1031 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1032 return False;
1035 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1036 winbind_validate_cache_cb);
1038 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1039 sizeof(myid))) {
1040 return False;
1043 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1045 if (num_replies == 0) {
1046 printf("No replies received\n");
1049 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1051 return num_replies;
1054 static BOOL do_reload_config(struct messaging_context *msg_ctx,
1055 const struct server_id pid,
1056 const int argc, const char **argv)
1058 if (argc != 1) {
1059 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1060 return False;
1063 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1066 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1068 fstring unix_name;
1069 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1070 fstrcpy(unix_name, name);
1071 strupper_m(unix_name);
1072 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1073 n->name_type = (unsigned int)type & 0xFF;
1074 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1077 static BOOL do_nodestatus(struct messaging_context *msg_ctx,
1078 const struct server_id pid,
1079 const int argc, const char **argv)
1081 struct packet_struct p;
1083 if (argc != 2) {
1084 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1085 return False;
1088 ZERO_STRUCT(p);
1090 p.ip = *interpret_addr2(argv[1]);
1091 p.port = 137;
1092 p.packet_type = NMB_PACKET;
1094 p.packet.nmb.header.name_trn_id = 10;
1095 p.packet.nmb.header.opcode = 0;
1096 p.packet.nmb.header.response = False;
1097 p.packet.nmb.header.nm_flags.bcast = False;
1098 p.packet.nmb.header.nm_flags.recursion_available = False;
1099 p.packet.nmb.header.nm_flags.recursion_desired = False;
1100 p.packet.nmb.header.nm_flags.trunc = False;
1101 p.packet.nmb.header.nm_flags.authoritative = False;
1102 p.packet.nmb.header.rcode = 0;
1103 p.packet.nmb.header.qdcount = 1;
1104 p.packet.nmb.header.ancount = 0;
1105 p.packet.nmb.header.nscount = 0;
1106 p.packet.nmb.header.arcount = 0;
1107 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1108 p.packet.nmb.question.question_type = 0x21;
1109 p.packet.nmb.question.question_class = 0x1;
1111 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1114 /* A list of message type supported */
1116 static const struct {
1117 const char *name; /* Option name */
1118 BOOL (*fn)(struct messaging_context *msg_ctx,
1119 const struct server_id pid,
1120 const int argc, const char **argv);
1121 const char *help; /* Short help text */
1122 } msg_types[] = {
1123 { "debug", do_debug, "Set debuglevel" },
1124 { "force-election", do_election,
1125 "Force a browse election" },
1126 { "ping", do_ping, "Elicit a response" },
1127 { "profile", do_profile, "" },
1128 { "inject", do_inject_fault,
1129 "Inject a fatal signal into a running smbd"},
1130 { "stacktrace", do_daemon_stack_trace,
1131 "Display a stack trace of a daemon" },
1132 { "profilelevel", do_profilelevel, "" },
1133 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1134 { "printnotify", do_printnotify, "Send a print notify message" },
1135 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1136 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1137 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1138 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1139 { "samrepl", do_samrepl, "Initiate SAM replication" },
1140 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1141 { "dmalloc-mark", do_dmalloc_mark, "" },
1142 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1143 { "shutdown", do_shutdown, "Shut down daemon" },
1144 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1145 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1146 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1147 { "online", do_winbind_online, "Ask winbind to go into online state"},
1148 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1149 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1150 { "dump-event-list", do_dump_event_list, "Dump event list"},
1151 { "validate-cache" , do_winbind_validate_cache,
1152 "Validate winbind's credential cache" },
1153 { "noop", do_noop, "Do nothing" },
1154 { NULL }
1157 /* Display usage information */
1159 static void usage(poptContext pc)
1161 int i;
1163 poptPrintHelp(pc, stderr, 0);
1165 fprintf(stderr, "\n");
1166 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1167 "process ID\n");
1169 fprintf(stderr, "\n");
1170 fprintf(stderr, "<message-type> is one of:\n");
1172 for (i = 0; msg_types[i].name; i++)
1173 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1174 msg_types[i].help);
1176 fprintf(stderr, "\n");
1178 exit(1);
1181 /* Return the pid number for a string destination */
1183 static struct server_id parse_dest(const char *dest)
1185 struct server_id result = {-1};
1186 pid_t pid;
1188 /* Zero is a special return value for broadcast smbd */
1190 if (strequal(dest, "smbd")) {
1191 return interpret_pid(MSG_BROADCAST_PID_STR);
1194 /* Try self - useful for testing */
1196 if (strequal(dest, "self")) {
1197 return pid_to_procid(sys_getpid());
1200 /* Fix winbind typo. */
1201 if (strequal(dest, "winbind")) {
1202 dest = "winbindd";
1206 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1207 /* Check for numeric pid number */
1209 result = interpret_pid(dest);
1211 /* Zero isn't valid if not smbd. */
1212 if (result.pid && procid_valid(&result)) {
1213 return result;
1217 /* Look up other destinations in pidfile directory */
1219 if ((pid = pidfile_pid(dest)) != 0) {
1220 return pid_to_procid(pid);
1223 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1225 return result;
1228 /* Execute smbcontrol command */
1230 static BOOL do_command(struct messaging_context *msg_ctx,
1231 int argc, const char **argv)
1233 const char *dest = argv[0], *command = argv[1];
1234 struct server_id pid;
1235 int i;
1237 /* Check destination */
1239 pid = parse_dest(dest);
1240 if (!procid_valid(&pid)) {
1241 return False;
1244 /* Check command */
1246 for (i = 0; msg_types[i].name; i++) {
1247 if (strequal(command, msg_types[i].name))
1248 return msg_types[i].fn(msg_ctx, pid,
1249 argc - 1, argv + 1);
1252 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1254 return False;
1257 static void smbcontrol_help(poptContext pc,
1258 enum poptCallbackReason preason,
1259 struct poptOption * poption,
1260 const char * parg,
1261 void * pdata)
1263 if (poption->shortName != '?') {
1264 poptPrintUsage(pc, stdout, 0);
1265 } else {
1266 usage(pc);
1269 exit(0);
1272 struct poptOption help_options[] = {
1273 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1274 NULL, NULL },
1275 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1276 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1277 { NULL }
1280 /* Main program */
1282 int main(int argc, const char **argv)
1284 poptContext pc;
1285 int opt;
1286 struct event_context *evt_ctx;
1287 struct messaging_context *msg_ctx;
1289 static struct poptOption long_options[] = {
1290 /* POPT_AUTOHELP */
1291 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1292 0, "Help options:", NULL },
1293 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1294 "Set timeout value in seconds", "TIMEOUT" },
1296 POPT_COMMON_SAMBA
1297 POPT_TABLEEND
1299 TALLOC_CTX *frame = talloc_stackframe();
1300 int ret = 0;
1302 load_case_tables();
1304 setup_logging(argv[0],True);
1306 /* Parse command line arguments using popt */
1308 pc = poptGetContext(
1309 "smbcontrol", argc, (const char **)argv, long_options, 0);
1311 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1312 "<parameters>");
1314 if (argc == 1)
1315 usage(pc);
1317 while ((opt = poptGetNextOpt(pc)) != -1) {
1318 switch(opt) {
1319 case 't': /* --timeout */
1320 break;
1321 default:
1322 fprintf(stderr, "Invalid option\n");
1323 poptPrintHelp(pc, stderr, 0);
1324 break;
1328 /* We should now have the remaining command line arguments in
1329 argv. The argc parameter should have been decremented to the
1330 correct value in the above switch statement. */
1332 argv = (const char **)poptGetArgs(pc);
1333 argc = 0;
1334 if (argv != NULL) {
1335 while (argv[argc] != NULL) {
1336 argc++;
1340 if (argc <= 1)
1341 usage(pc);
1343 lp_load(dyn_CONFIGFILE,False,False,False,True);
1345 /* Need to invert sense of return code -- samba
1346 * routines mostly return True==1 for success, but
1347 * shell needs 0. */
1349 if (!(evt_ctx = event_context_init(NULL)) ||
1350 !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1351 fprintf(stderr, "could not init messaging context\n");
1352 TALLOC_FREE(frame);
1353 exit(1);
1356 ret = !do_command(msg_ctx, argc, argv);
1357 TALLOC_FREE(frame);
1358 return ret;