r17915: Saturn fixes
[Samba/gbeck.git] / source / utils / smbcontrol.c
blob0c6a1341c037cb16128cc0bc4b4c4b2bbd76e7f7
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 2 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, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "includes.h"
29 #if HAVE_LIBUNWIND_H
30 #include <libunwind.h>
31 #endif
33 #if HAVE_LIBUNWIND_PTRACE_H
34 #include <libunwind-ptrace.h>
35 #endif
37 #if HAVE_SYS_PTRACE_H
38 #include <sys/ptrace.h>
39 #endif
41 /* Default timeout value when waiting for replies (in seconds) */
43 #define DEFAULT_TIMEOUT 10
45 static int timeout = DEFAULT_TIMEOUT;
46 static int num_replies; /* Used by message callback fns */
48 /* Send a message to a destination pid. Zero means broadcast smbd. */
50 static BOOL send_message(struct process_id pid, int msg_type,
51 const void *buf, int len,
52 BOOL duplicates)
54 TDB_CONTEXT *tdb;
55 BOOL ret;
56 int n_sent = 0;
58 if (!message_init())
59 return False;
61 if (procid_to_pid(&pid) != 0)
62 return message_send_pid(pid, msg_type, buf, len, duplicates);
64 tdb = tdb_open_log(lock_path("connections.tdb"), 0,
65 TDB_DEFAULT, O_RDWR, 0);
66 if (!tdb) {
67 fprintf(stderr,"Failed to open connections database"
68 ": %s\n", strerror(errno));
69 return False;
72 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
73 &n_sent);
74 DEBUG(10,("smbcontrol/send_message: broadcast message to "
75 "%d processes\n", n_sent));
77 tdb_close(tdb);
79 return ret;
82 /* Wait for one or more reply messages */
84 static void wait_replies(BOOL multiple_replies)
86 time_t start_time = time(NULL);
88 /* Wait around a bit. This is pretty disgusting - we have to
89 busy-wait here as there is no nicer way to do it. */
91 do {
92 message_dispatch();
93 if (num_replies > 0 && !multiple_replies)
94 break;
95 sleep(1);
96 } while (timeout - (time(NULL) - start_time) > 0);
99 /* Message handler callback that displays the PID and a string on stdout */
101 static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len)
103 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
104 (int)len, (const char *)buf);
105 num_replies++;
108 /* Message handler callback that displays a string on stdout */
110 static void print_string_cb(int msg_type, struct process_id pid,
111 void *buf, size_t len)
113 printf("%.*s", (int)len, (const char *)buf);
114 num_replies++;
117 /* Send no message. Useful for testing. */
119 static BOOL do_noop(const struct process_id pid,
120 const int argc, const char **argv)
122 if (argc != 1) {
123 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
124 return False;
127 /* Move along, nothing to see here */
129 return True;
132 /* Send a debug string */
134 static BOOL do_debug(const struct process_id pid,
135 const int argc, const char **argv)
137 if (argc != 2) {
138 fprintf(stderr, "Usage: smbcontrol <dest> debug "
139 "<debug-string>\n");
140 return False;
143 return send_message(
144 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
147 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
149 /* Return the name of a process given it's PID. This will only work on Linux,
150 * but that's probably moot since this whole stack tracing implementatino is
151 * Linux-specific anyway.
153 static const char * procname(pid_t pid, char * buf, size_t bufsz)
155 char path[64];
156 FILE * fp;
158 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
159 (unsigned long long)pid);
160 if ((fp = fopen(path, "r")) == NULL) {
161 return NULL;
164 fgets(buf, bufsz, fp);
166 fclose(fp);
167 return buf;
170 static void print_stack_trace(pid_t pid, int * count)
172 void * pinfo = NULL;
173 unw_addr_space_t aspace = NULL;
174 unw_cursor_t cursor;
175 unw_word_t ip, sp;
177 char nbuf[256];
178 unw_word_t off;
180 int ret;
182 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
183 fprintf(stderr,
184 "Failed to attach to process %llu: %s\n",
185 (unsigned long long)pid, strerror(errno));
186 return;
189 /* Wait until the attach is complete. */
190 waitpid(pid, NULL, 0);
192 if (((pinfo = _UPT_create(pid)) == NULL) ||
193 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
194 /* Probably out of memory. */
195 fprintf(stderr,
196 "Unable to initialize stack unwind for process %llu\n",
197 (unsigned long long)pid);
198 goto cleanup;
201 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
202 fprintf(stderr,
203 "Unable to unwind stack for process %llu: %s\n",
204 (unsigned long long)pid, unw_strerror(ret));
205 goto cleanup;
208 if (*count > 0) {
209 printf("\n");
212 if (procname(pid, nbuf, sizeof(nbuf))) {
213 printf("Stack trace for process %llu (%s):\n",
214 (unsigned long long)pid, nbuf);
215 } else {
216 printf("Stack trace for process %llu:\n",
217 (unsigned long long)pid);
220 while (unw_step(&cursor) > 0) {
221 ip = sp = off = 0;
222 unw_get_reg(&cursor, UNW_REG_IP, &ip);
223 unw_get_reg(&cursor, UNW_REG_SP, &sp);
225 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
226 if (ret != 0 && ret != -UNW_ENOMEM) {
227 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
229 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
230 nbuf, (long long)off, (long long)ip,
231 (long long)sp);
234 (*count)++;
236 cleanup:
237 if (aspace) {
238 unw_destroy_addr_space(aspace);
241 if (pinfo) {
242 _UPT_destroy(pinfo);
245 ptrace(PTRACE_DETACH, pid, NULL, NULL);
248 static int stack_trace_connection(TDB_CONTEXT * tdb, TDB_DATA key,
249 TDB_DATA data, void * priv)
251 struct connections_data conn;
253 if (data.dsize != sizeof(conn))
254 return 0;
256 memcpy(&conn, data.dptr, sizeof(conn));
257 print_stack_trace(procid_to_pid(&conn.pid), (int *)priv);
259 return 0;
262 static BOOL do_daemon_stack_trace(const struct process_id pid,
263 const int argc, const char **argv)
265 fprintf(stderr,
266 "Daemon stack tracing is not supported on this platform\n");
267 return False;
269 pid_t dest;
270 int count = 0;
272 if (argc != 1) {
273 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
274 return False;
277 dest = procid_to_pid(&pid);
279 if (dest != 0) {
280 /* It would be nice to be able to make sure that this PID is
281 * the PID of a smbd/winbind/nmbd process, not some random PID
282 * the user liked the look of. It doesn't seem like it's worth
283 * the effort at the moment, however.
285 print_stack_trace(dest, &count);
286 } else {
287 TDB_CONTEXT * tdb;
289 tdb = tdb_open_log(lock_path("connections.tdb"), 0,
290 TDB_DEFAULT, O_RDONLY, 0);
291 if (!tdb) {
292 fprintf(stderr,
293 "Failed to open connections database: %s\n",
294 strerror(errno));
295 return False;
298 tdb_traverse(tdb, stack_trace_connection, &count);
299 tdb_close(tdb);
302 return True;
305 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
307 static BOOL do_daemon_stack_trace(const struct process_id pid,
308 const int argc, const char **argv)
310 fprintf(stderr,
311 "Daemon stack tracing is not supported on this platform\n");
312 return False;
315 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
317 /* Inject a fault (fatal signal) into a running smbd */
319 static BOOL do_inject_fault(const struct process_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(pid, MSG_SMB_INJECT_FAULT,
353 &sig, sizeof(int), False);
355 #endif /* DEVELOPER */
358 /* Force a browser election */
360 static BOOL do_election(const struct process_id pid,
361 const int argc, const char **argv)
363 if (argc != 1) {
364 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
365 return False;
368 return send_message(
369 pid, MSG_FORCE_ELECTION, NULL, 0, False);
372 /* Ping a samba daemon process */
374 static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len)
376 char *src_string = procid_str(NULL, &pid);
377 printf("PONG from pid %s\n", src_string);
378 TALLOC_FREE(src_string);
379 num_replies++;
382 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
384 if (argc != 1) {
385 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
386 return False;
389 /* Send a message and register our interest in a reply */
391 if (!send_message(pid, MSG_PING, NULL, 0, False))
392 return False;
394 message_register(MSG_PONG, pong_cb);
396 wait_replies(procid_to_pid(&pid) == 0);
398 /* No replies were received within the timeout period */
400 if (num_replies == 0)
401 printf("No replies received\n");
403 message_deregister(MSG_PONG);
405 return num_replies;
408 /* Set profiling options */
410 static BOOL do_profile(const struct process_id pid,
411 const int argc, const char **argv)
413 int v;
415 if (argc != 2) {
416 fprintf(stderr, "Usage: smbcontrol <dest> profile "
417 "<off|count|on|flush>\n");
418 return False;
421 if (strcmp(argv[1], "off") == 0) {
422 v = 0;
423 } else if (strcmp(argv[1], "count") == 0) {
424 v = 1;
425 } else if (strcmp(argv[1], "on") == 0) {
426 v = 2;
427 } else if (strcmp(argv[1], "flush") == 0) {
428 v = 3;
429 } else {
430 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
431 return False;
434 return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
437 /* Return the profiling level */
439 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len)
441 int level;
442 const char *s;
444 num_replies++;
446 if (len != sizeof(int)) {
447 fprintf(stderr, "invalid message length %ld returned\n",
448 (unsigned long)len);
449 return;
452 memcpy(&level, buf, sizeof(int));
454 switch (level) {
455 case 0:
456 s = "not enabled";
457 break;
458 case 1:
459 s = "off";
460 break;
461 case 3:
462 s = "count only";
463 break;
464 case 7:
465 s = "count and time";
466 break;
467 default:
468 s = "BOGUS";
469 break;
472 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
475 static void profilelevel_rqst(int msg_type, struct process_id pid,
476 void *buf, size_t len)
478 int v = 0;
480 /* Send back a dummy reply */
482 send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
485 static BOOL do_profilelevel(const struct process_id pid,
486 const int argc, const char **argv)
488 if (argc != 1) {
489 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
490 return False;
493 /* Send a message and register our interest in a reply */
495 if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
496 return False;
498 message_register(MSG_PROFILELEVEL, profilelevel_cb);
499 message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
501 wait_replies(procid_to_pid(&pid) == 0);
503 /* No replies were received within the timeout period */
505 if (num_replies == 0)
506 printf("No replies received\n");
508 message_deregister(MSG_PROFILE);
510 return num_replies;
513 /* Display debug level settings */
515 static BOOL do_debuglevel(const struct process_id pid,
516 const int argc, const char **argv)
518 if (argc != 1) {
519 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
520 return False;
523 /* Send a message and register our interest in a reply */
525 if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
526 return False;
528 message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
530 wait_replies(procid_to_pid(&pid) == 0);
532 /* No replies were received within the timeout period */
534 if (num_replies == 0)
535 printf("No replies received\n");
537 message_deregister(MSG_DEBUGLEVEL);
539 return num_replies;
542 /* Send a print notify message */
544 static BOOL do_printnotify(const struct process_id pid,
545 const int argc, const char **argv)
547 const char *cmd;
549 /* Check for subcommand */
551 if (argc == 1) {
552 fprintf(stderr, "Must specify subcommand:\n");
553 fprintf(stderr, "\tqueuepause <printername>\n");
554 fprintf(stderr, "\tqueueresume <printername>\n");
555 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
556 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
557 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
558 fprintf(stderr, "\tprinter <printername> <comment|port|"
559 "driver> <value>\n");
561 return False;
564 cmd = argv[1];
566 if (strcmp(cmd, "queuepause") == 0) {
568 if (argc != 3) {
569 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
570 " queuepause <printername>\n");
571 return False;
574 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
576 goto send;
578 } else if (strcmp(cmd, "queueresume") == 0) {
580 if (argc != 3) {
581 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
582 " queuereume <printername>\n");
583 return False;
586 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
588 goto send;
590 } else if (strcmp(cmd, "jobpause") == 0) {
591 int jobid;
593 if (argc != 4) {
594 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
595 " jobpause <printername> <unix-jobid>\n");
596 return False;
599 jobid = atoi(argv[3]);
601 notify_job_status_byname(
602 argv[2], jobid, JOB_STATUS_PAUSED,
603 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
605 goto send;
607 } else if (strcmp(cmd, "jobresume") == 0) {
608 int jobid;
610 if (argc != 4) {
611 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
612 " jobpause <printername> <unix-jobid>\n");
613 return False;
616 jobid = atoi(argv[3]);
618 notify_job_status_byname(
619 argv[2], jobid, JOB_STATUS_QUEUED,
620 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
622 goto send;
624 } else if (strcmp(cmd, "jobdelete") == 0) {
625 int jobid;
627 if (argc != 4) {
628 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
629 " jobpause <printername> <unix-jobid>\n");
630 return False;
633 jobid = atoi(argv[3]);
635 notify_job_status_byname(
636 argv[2], jobid, JOB_STATUS_DELETING,
637 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
639 notify_job_status_byname(
640 argv[2], jobid, JOB_STATUS_DELETING|
641 JOB_STATUS_DELETED,
642 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
644 goto send;
646 } else if (strcmp(cmd, "printer") == 0) {
647 uint32 attribute;
649 if (argc != 5) {
650 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
651 "printer <printername> <comment|port|driver> "
652 "<value>\n");
653 return False;
656 if (strcmp(argv[3], "comment") == 0) {
657 attribute = PRINTER_NOTIFY_COMMENT;
658 } else if (strcmp(argv[3], "port") == 0) {
659 attribute = PRINTER_NOTIFY_PORT_NAME;
660 } else if (strcmp(argv[3], "driver") == 0) {
661 attribute = PRINTER_NOTIFY_DRIVER_NAME;
662 } else {
663 fprintf(stderr, "Invalid printer command '%s'\n",
664 argv[3]);
665 return False;
668 notify_printer_byname(argv[2], attribute,
669 CONST_DISCARD(char *, argv[4]));
671 goto send;
674 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
675 return False;
677 send:
678 print_notify_send_messages(0);
679 return True;
682 /* Close a share */
684 static BOOL do_closeshare(const struct process_id pid,
685 const int argc, const char **argv)
687 if (argc != 2) {
688 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
689 "<sharename>\n");
690 return False;
693 return send_message(
694 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
697 /* Force a SAM synchronisation */
699 static BOOL do_samsync(const struct process_id pid,
700 const int argc, const char **argv)
702 if (argc != 1) {
703 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
704 return False;
707 return send_message(
708 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
711 /* Force a SAM replication */
713 static BOOL do_samrepl(const struct process_id pid,
714 const int argc, const char **argv)
716 if (argc != 1) {
717 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
718 return False;
721 return send_message(
722 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
725 /* Display talloc pool usage */
727 static BOOL do_poolusage(const struct process_id pid,
728 const int argc, const char **argv)
730 if (argc != 1) {
731 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
732 return False;
735 message_register(MSG_POOL_USAGE, print_string_cb);
737 /* Send a message and register our interest in a reply */
739 if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
740 return False;
742 wait_replies(procid_to_pid(&pid) == 0);
744 /* No replies were received within the timeout period */
746 if (num_replies == 0)
747 printf("No replies received\n");
749 message_deregister(MSG_POOL_USAGE);
751 return num_replies;
754 /* Perform a dmalloc mark */
756 static BOOL do_dmalloc_mark(const struct process_id pid,
757 const int argc, const char **argv)
759 if (argc != 1) {
760 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
761 return False;
764 return send_message(
765 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
768 /* Perform a dmalloc changed */
770 static BOOL do_dmalloc_changed(const struct process_id pid,
771 const int argc, const char **argv)
773 if (argc != 1) {
774 fprintf(stderr, "Usage: smbcontrol <dest> "
775 "dmalloc-log-changed\n");
776 return False;
779 return send_message(
780 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
783 /* Shutdown a server process */
785 static BOOL do_shutdown(const struct process_id pid,
786 const int argc, const char **argv)
788 if (argc != 1) {
789 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
790 return False;
793 return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
796 /* Notify a driver upgrade */
798 static BOOL do_drvupgrade(const struct process_id pid,
799 const int argc, const char **argv)
801 if (argc != 2) {
802 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
803 "<driver-name>\n");
804 return False;
807 return send_message(
808 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
811 static BOOL do_winbind_online(const struct process_id pid,
812 const int argc, const char **argv)
814 TDB_CONTEXT *tdb;
816 if (argc != 1) {
817 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
818 return False;
821 if (!lp_winbind_offline_logon()) {
822 fprintf(stderr, "The parameter \"winbind offline logon\" must "
823 "be set in the [global] section of smb.conf for this "
824 "command to be allowed.\n");
825 return False;
828 /* Remove the entry in the winbindd_cache tdb to tell a later
829 starting winbindd that we're online. */
831 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
832 if (!tdb) {
833 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
834 lock_path("winbindd_cache.tdb"));
835 return False;
838 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
839 tdb_close(tdb);
841 return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
844 static BOOL do_winbind_offline(const struct process_id pid,
845 const int argc, const char **argv)
847 TDB_CONTEXT *tdb;
848 BOOL ret = False;
849 int retry = 0;
851 if (argc != 1) {
852 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
853 return False;
856 if (!lp_winbind_offline_logon()) {
857 fprintf(stderr, "The parameter \"winbind offline logon\" must "
858 "be set in the [global] section of smb.conf for this "
859 "command to be allowed.\n");
860 return False;
863 /* Create an entry in the winbindd_cache tdb to tell a later
864 starting winbindd that we're offline. We may actually create
865 it here... */
867 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
868 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
869 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
871 if (!tdb) {
872 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
873 lock_path("winbindd_cache.tdb"));
874 return False;
877 /* There's a potential race condition that if a child
878 winbindd detects a domain is online at the same time
879 we're trying to tell it to go offline that it might
880 delete the record we add between us adding it and
881 sending the message. Minimize this by retrying up to
882 5 times. */
884 for (retry = 0; retry < 5; retry++) {
885 int err;
886 TDB_DATA d;
887 ZERO_STRUCT(d);
888 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
890 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
892 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
893 tdb->ecode = TDB_SUCCESS;
894 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
896 /* As this is a key with no data we don't need to free, we
897 check for existence by looking at tdb_err. */
899 err = tdb_error(tdb);
901 if (err == TDB_ERR_NOEXIST) {
902 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
903 } else {
904 break;
908 tdb_close(tdb);
909 return ret;
912 static BOOL do_winbind_onlinestatus(const struct process_id pid,
913 const int argc, const char **argv)
915 struct process_id myid;
917 myid = pid_to_procid(sys_getpid());
919 if (argc != 1) {
920 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
921 return False;
924 message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb);
926 if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False))
927 return False;
929 wait_replies(procid_to_pid(&pid) == 0);
931 /* No replies were received within the timeout period */
933 if (num_replies == 0)
934 printf("No replies received\n");
936 message_deregister(MSG_WINBIND_ONLINESTATUS);
938 return num_replies;
942 static BOOL do_reload_config(const struct process_id pid,
943 const int argc, const char **argv)
945 if (argc != 1) {
946 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
947 return False;
950 return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
953 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
955 fstring unix_name;
956 memset( (char *)n, '\0', sizeof(struct nmb_name) );
957 fstrcpy(unix_name, name);
958 strupper_m(unix_name);
959 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
960 n->name_type = (unsigned int)type & 0xFF;
961 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
964 static BOOL do_nodestatus(const struct process_id pid,
965 const int argc, const char **argv)
967 struct packet_struct p;
969 if (argc != 2) {
970 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
971 return False;
974 ZERO_STRUCT(p);
976 p.ip = *interpret_addr2(argv[1]);
977 p.port = 137;
978 p.packet_type = NMB_PACKET;
980 p.packet.nmb.header.name_trn_id = 10;
981 p.packet.nmb.header.opcode = 0;
982 p.packet.nmb.header.response = False;
983 p.packet.nmb.header.nm_flags.bcast = False;
984 p.packet.nmb.header.nm_flags.recursion_available = False;
985 p.packet.nmb.header.nm_flags.recursion_desired = False;
986 p.packet.nmb.header.nm_flags.trunc = False;
987 p.packet.nmb.header.nm_flags.authoritative = False;
988 p.packet.nmb.header.rcode = 0;
989 p.packet.nmb.header.qdcount = 1;
990 p.packet.nmb.header.ancount = 0;
991 p.packet.nmb.header.nscount = 0;
992 p.packet.nmb.header.arcount = 0;
993 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
994 p.packet.nmb.question.question_type = 0x21;
995 p.packet.nmb.question.question_class = 0x1;
997 return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
1000 /* A list of message type supported */
1002 static const struct {
1003 const char *name; /* Option name */
1004 BOOL (*fn)(const struct process_id pid,
1005 const int argc, const char **argv);
1006 const char *help; /* Short help text */
1007 } msg_types[] = {
1008 { "debug", do_debug, "Set debuglevel" },
1009 { "force-election", do_election,
1010 "Force a browse election" },
1011 { "ping", do_ping, "Elicit a response" },
1012 { "profile", do_profile, "" },
1013 { "inject", do_inject_fault,
1014 "Inject a fatal signal into a running smbd"},
1015 { "stacktrace", do_daemon_stack_trace,
1016 "Display a stack trace of a daemon" },
1017 { "profilelevel", do_profilelevel, "" },
1018 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1019 { "printnotify", do_printnotify, "Send a print notify message" },
1020 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1021 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1022 { "samrepl", do_samrepl, "Initiate SAM replication" },
1023 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1024 { "dmalloc-mark", do_dmalloc_mark, "" },
1025 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1026 { "shutdown", do_shutdown, "Shut down daemon" },
1027 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1028 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1029 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1030 { "online", do_winbind_online, "Ask winbind to go into online state"},
1031 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1032 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1033 { "noop", do_noop, "Do nothing" },
1034 { NULL }
1037 /* Display usage information */
1039 static void usage(poptContext *pc)
1041 int i;
1043 poptPrintHelp(*pc, stderr, 0);
1045 fprintf(stderr, "\n");
1046 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1047 "process ID\n");
1049 fprintf(stderr, "\n");
1050 fprintf(stderr, "<message-type> is one of:\n");
1052 for (i = 0; msg_types[i].name; i++)
1053 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1054 msg_types[i].help);
1056 fprintf(stderr, "\n");
1058 exit(1);
1061 /* Return the pid number for a string destination */
1063 static struct process_id parse_dest(const char *dest)
1065 struct process_id result = {-1};
1066 pid_t pid;
1068 /* Zero is a special return value for broadcast smbd */
1070 if (strequal(dest, "smbd")) {
1071 return interpret_pid("0");
1074 /* Try self - useful for testing */
1076 if (strequal(dest, "self")) {
1077 return pid_to_procid(sys_getpid());
1080 /* Fix winbind typo. */
1081 if (strequal(dest, "winbind")) {
1082 dest = "winbindd";
1086 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1087 /* Check for numeric pid number */
1089 result = interpret_pid(dest);
1091 /* Zero isn't valid if not smbd. */
1092 if (result.pid && procid_valid(&result)) {
1093 return result;
1097 /* Look up other destinations in pidfile directory */
1099 if ((pid = pidfile_pid(dest)) != 0) {
1100 return pid_to_procid(pid);
1103 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1105 return result;
1108 /* Execute smbcontrol command */
1110 static BOOL do_command(int argc, const char **argv)
1112 const char *dest = argv[0], *command = argv[1];
1113 struct process_id pid;
1114 int i;
1116 /* Check destination */
1118 pid = parse_dest(dest);
1119 if (!procid_valid(&pid)) {
1120 return False;
1123 /* Check command */
1125 for (i = 0; msg_types[i].name; i++) {
1126 if (strequal(command, msg_types[i].name))
1127 return msg_types[i].fn(pid, argc - 1, argv + 1);
1130 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1132 return False;
1135 /* Main program */
1137 int main(int argc, const char **argv)
1139 poptContext pc;
1140 int opt;
1142 static struct poptOption wbinfo_options[] = {
1143 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1144 "Set timeout value in seconds", "TIMEOUT" },
1146 { "configfile", 's', POPT_ARG_STRING, NULL, 's',
1147 "Use alternative configuration file", "CONFIGFILE" },
1149 POPT_TABLEEND
1152 struct poptOption options[] = {
1153 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0,
1154 "Options" },
1156 POPT_AUTOHELP
1157 POPT_COMMON_VERSION
1158 POPT_TABLEEND
1161 load_case_tables();
1163 setup_logging(argv[0],True);
1165 /* Parse command line arguments using popt */
1167 pc = poptGetContext(
1168 "smbcontrol", argc, (const char **)argv, options, 0);
1170 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1171 "<parameters>");
1173 if (argc == 1)
1174 usage(&pc);
1176 while ((opt = poptGetNextOpt(pc)) != -1) {
1177 switch(opt) {
1178 case 't': /* --timeout */
1179 argc -= 2;
1180 break;
1181 case 's': /* --configfile */
1182 pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
1183 argc -= 2;
1184 break;
1185 default:
1186 fprintf(stderr, "Invalid option\n");
1187 poptPrintHelp(pc, stderr, 0);
1188 break;
1192 /* We should now have the remaining command line arguments in
1193 argv. The argc parameter should have been decremented to the
1194 correct value in the above switch statement. */
1196 argv = (const char **)poptGetArgs(pc);
1197 argc--; /* Don't forget about argv[0] */
1199 if (argc == 1)
1200 usage(&pc);
1202 lp_load(dyn_CONFIGFILE,False,False,False,True);
1204 /* Need to invert sense of return code -- samba
1205 * routines mostly return True==1 for success, but
1206 * shell needs 0. */
1208 return !do_command(argc, argv);