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
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /* Default timeout value when waiting for replies (in seconds) */
30 #define DEFAULT_TIMEOUT 10
32 static int timeout = DEFAULT_TIMEOUT;
33 static int num_replies; /* Used by message callback fns */
35 /* Send a message to a destination pid. Zero means broadcast smbd. */
37 static BOOL send_message(struct process_id pid, int msg_type,
38 const void *buf, int len,
48 if (procid_to_pid(&pid) != 0)
49 return message_send_pid(pid, msg_type, buf, len, duplicates);
51 tdb = tdb_open_log(lock_path("connections.tdb"), 0,
52 TDB_DEFAULT, O_RDWR, 0);
54 fprintf(stderr,"Failed to open connections database"
55 ": %s\n", strerror(errno));
59 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
61 DEBUG(10,("smbcontrol/send_message: broadcast message to "
62 "%d processes\n", n_sent));
69 /* Wait for one or more reply messages */
71 static void wait_replies(BOOL multiple_replies)
73 time_t start_time = time(NULL);
75 /* Wait around a bit. This is pretty disgusting - we have to
76 busy-wait here as there is no nicer way to do it. */
80 if (num_replies > 0 && !multiple_replies)
83 } while (timeout - (time(NULL) - start_time) > 0);
86 /* Message handler callback that displays the PID and a string on stdout */
88 static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len)
90 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
91 (int)len, (const char *)buf);
95 /* Message handler callback that displays a string on stdout */
97 static void print_string_cb(int msg_type, struct process_id pid,
98 void *buf, size_t len)
100 printf("%.*s", (int)len, (const char *)buf);
104 /* Send no message. Useful for testing. */
106 static BOOL do_noop(const struct process_id pid,
107 const int argc, const char **argv)
110 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
114 /* Move along, nothing to see here */
119 /* Send a debug string */
121 static BOOL do_debug(const struct process_id pid,
122 const int argc, const char **argv)
125 fprintf(stderr, "Usage: smbcontrol <dest> debug "
131 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
134 /* Inject a fault (fata signal) into a running smbd */
136 static BOOL do_inject_fault(const struct process_id pid,
137 const int argc, const char **argv)
140 fprintf(stderr, "Usage: smbcontrol <dest> inject "
141 "<bus|hup|term|internal|segv>\n");
146 fprintf(stderr, "Fault injection is only available in"
147 "developer builds\n");
149 #else /* DEVELOPER */
153 if (strcmp(argv[1], "bus") == 0) {
155 } else if (strcmp(argv[1], "hup") == 0) {
157 } else if (strcmp(argv[1], "term") == 0) {
159 } else if (strcmp(argv[1], "segv") == 0) {
161 } else if (strcmp(argv[1], "internal") == 0) {
162 /* Force an internal error, ie. an unclean exit. */
165 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
169 return send_message(pid, MSG_SMB_INJECT_FAULT,
170 &sig, sizeof(int), False);
172 #endif /* DEVELOPER */
175 /* Force a browser election */
177 static BOOL do_election(const struct process_id pid,
178 const int argc, const char **argv)
181 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
186 pid, MSG_FORCE_ELECTION, NULL, 0, False);
189 /* Ping a samba daemon process */
191 static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len)
193 char *src_string = procid_str(NULL, &pid);
194 printf("PONG from pid %s\n", src_string);
195 TALLOC_FREE(src_string);
199 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
202 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
206 /* Send a message and register our interest in a reply */
208 if (!send_message(pid, MSG_PING, NULL, 0, False))
211 message_register(MSG_PONG, pong_cb);
213 wait_replies(procid_to_pid(&pid) == 0);
215 /* No replies were received within the timeout period */
217 if (num_replies == 0)
218 printf("No replies received\n");
220 message_deregister(MSG_PONG);
225 /* Set profiling options */
227 static BOOL do_profile(const struct process_id pid,
228 const int argc, const char **argv)
233 fprintf(stderr, "Usage: smbcontrol <dest> profile "
234 "<off|count|on|flush>\n");
238 if (strcmp(argv[1], "off") == 0) {
240 } else if (strcmp(argv[1], "count") == 0) {
242 } else if (strcmp(argv[1], "on") == 0) {
244 } else if (strcmp(argv[1], "flush") == 0) {
247 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
251 return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
254 /* Return the profiling level */
256 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len)
263 if (len != sizeof(int)) {
264 fprintf(stderr, "invalid message length %ld returned\n",
269 memcpy(&level, buf, sizeof(int));
282 s = "count and time";
289 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
292 static void profilelevel_rqst(int msg_type, struct process_id pid,
293 void *buf, size_t len)
297 /* Send back a dummy reply */
299 send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
302 static BOOL do_profilelevel(const struct process_id pid,
303 const int argc, const char **argv)
306 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
310 /* Send a message and register our interest in a reply */
312 if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
315 message_register(MSG_PROFILELEVEL, profilelevel_cb);
316 message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
318 wait_replies(procid_to_pid(&pid) == 0);
320 /* No replies were received within the timeout period */
322 if (num_replies == 0)
323 printf("No replies received\n");
325 message_deregister(MSG_PROFILE);
330 /* Display debug level settings */
332 static BOOL do_debuglevel(const struct process_id pid,
333 const int argc, const char **argv)
336 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
340 /* Send a message and register our interest in a reply */
342 if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
345 message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
347 wait_replies(procid_to_pid(&pid) == 0);
349 /* No replies were received within the timeout period */
351 if (num_replies == 0)
352 printf("No replies received\n");
354 message_deregister(MSG_DEBUGLEVEL);
359 /* Send a print notify message */
361 static BOOL do_printnotify(const struct process_id pid,
362 const int argc, const char **argv)
366 /* Check for subcommand */
369 fprintf(stderr, "Must specify subcommand:\n");
370 fprintf(stderr, "\tqueuepause <printername>\n");
371 fprintf(stderr, "\tqueueresume <printername>\n");
372 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
373 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
374 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
375 fprintf(stderr, "\tprinter <printername> <comment|port|"
376 "driver> <value>\n");
383 if (strcmp(cmd, "queuepause") == 0) {
386 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
387 " queuepause <printername>\n");
391 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
395 } else if (strcmp(cmd, "queueresume") == 0) {
398 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
399 " queuereume <printername>\n");
403 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
407 } else if (strcmp(cmd, "jobpause") == 0) {
411 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
412 " jobpause <printername> <unix-jobid>\n");
416 jobid = atoi(argv[3]);
418 notify_job_status_byname(
419 argv[2], jobid, JOB_STATUS_PAUSED,
420 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
424 } else if (strcmp(cmd, "jobresume") == 0) {
428 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
429 " jobpause <printername> <unix-jobid>\n");
433 jobid = atoi(argv[3]);
435 notify_job_status_byname(
436 argv[2], jobid, JOB_STATUS_QUEUED,
437 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
441 } else if (strcmp(cmd, "jobdelete") == 0) {
445 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
446 " jobpause <printername> <unix-jobid>\n");
450 jobid = atoi(argv[3]);
452 notify_job_status_byname(
453 argv[2], jobid, JOB_STATUS_DELETING,
454 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
456 notify_job_status_byname(
457 argv[2], jobid, JOB_STATUS_DELETING|
459 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
463 } else if (strcmp(cmd, "printer") == 0) {
467 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
468 "printer <printername> <comment|port|driver> "
473 if (strcmp(argv[3], "comment") == 0) {
474 attribute = PRINTER_NOTIFY_COMMENT;
475 } else if (strcmp(argv[3], "port") == 0) {
476 attribute = PRINTER_NOTIFY_PORT_NAME;
477 } else if (strcmp(argv[3], "driver") == 0) {
478 attribute = PRINTER_NOTIFY_DRIVER_NAME;
480 fprintf(stderr, "Invalid printer command '%s'\n",
485 notify_printer_byname(argv[2], attribute,
486 CONST_DISCARD(char *, argv[4]));
491 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
495 print_notify_send_messages(0);
501 static BOOL do_closeshare(const struct process_id pid,
502 const int argc, const char **argv)
505 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
511 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
514 /* Force a SAM synchronisation */
516 static BOOL do_samsync(const struct process_id pid,
517 const int argc, const char **argv)
520 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
525 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
528 /* Force a SAM replication */
530 static BOOL do_samrepl(const struct process_id pid,
531 const int argc, const char **argv)
534 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
539 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
542 /* Display talloc pool usage */
544 static BOOL do_poolusage(const struct process_id pid,
545 const int argc, const char **argv)
548 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
552 message_register(MSG_POOL_USAGE, print_string_cb);
554 /* Send a message and register our interest in a reply */
556 if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
559 wait_replies(procid_to_pid(&pid) == 0);
561 /* No replies were received within the timeout period */
563 if (num_replies == 0)
564 printf("No replies received\n");
566 message_deregister(MSG_POOL_USAGE);
571 /* Perform a dmalloc mark */
573 static BOOL do_dmalloc_mark(const struct process_id pid,
574 const int argc, const char **argv)
577 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
582 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
585 /* Perform a dmalloc changed */
587 static BOOL do_dmalloc_changed(const struct process_id pid,
588 const int argc, const char **argv)
591 fprintf(stderr, "Usage: smbcontrol <dest> "
592 "dmalloc-log-changed\n");
597 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
600 /* Shutdown a server process */
602 static BOOL do_shutdown(const struct process_id pid,
603 const int argc, const char **argv)
606 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
610 return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
613 /* Notify a driver upgrade */
615 static BOOL do_drvupgrade(const struct process_id pid,
616 const int argc, const char **argv)
619 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
625 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
628 static BOOL do_winbind_online(const struct process_id pid,
629 const int argc, const char **argv)
634 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
638 if (!lp_winbind_offline_logon()) {
639 fprintf(stderr, "The parameter \"winbind offline logon\" must "
640 "be set in the [global] section of smb.conf for this "
641 "command to be allowed.\n");
645 /* Remove the entry in the winbindd_cache tdb to tell a later
646 starting winbindd that we're online. */
648 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
650 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
651 lock_path("winbindd_cache.tdb"));
655 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
658 return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
661 static BOOL do_winbind_offline(const struct process_id pid,
662 const int argc, const char **argv)
669 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
673 if (!lp_winbind_offline_logon()) {
674 fprintf(stderr, "The parameter \"winbind offline logon\" must "
675 "be set in the [global] section of smb.conf for this "
676 "command to be allowed.\n");
680 /* Create an entry in the winbindd_cache tdb to tell a later
681 starting winbindd that we're offline. We may actually create
684 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
685 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
686 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
689 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
690 lock_path("winbindd_cache.tdb"));
694 /* There's a potential race condition that if a child
695 winbindd detects a domain is online at the same time
696 we're trying to tell it to go offline that it might
697 delete the record we add between us adding it and
698 sending the message. Minimize this by retrying up to
701 for (retry = 0; retry < 5; retry++) {
705 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
707 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
709 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
711 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
713 /* As this is a key with no data we don't need to free, we
714 check for existence by looking at tdb_err. */
716 err = tdb_error(tdb);
718 if (err == TDB_ERR_NOEXIST) {
719 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
729 static BOOL do_reload_config(const struct process_id pid,
730 const int argc, const char **argv)
733 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
737 return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
740 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
743 memset( (char *)n, '\0', sizeof(struct nmb_name) );
744 fstrcpy(unix_name, name);
745 strupper_m(unix_name);
746 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
747 n->name_type = (unsigned int)type & 0xFF;
748 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
751 static BOOL do_nodestatus(const struct process_id pid,
752 const int argc, const char **argv)
754 struct packet_struct p;
757 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
763 p.ip = *interpret_addr2(argv[1]);
765 p.packet_type = NMB_PACKET;
767 p.packet.nmb.header.name_trn_id = 10;
768 p.packet.nmb.header.opcode = 0;
769 p.packet.nmb.header.response = False;
770 p.packet.nmb.header.nm_flags.bcast = False;
771 p.packet.nmb.header.nm_flags.recursion_available = False;
772 p.packet.nmb.header.nm_flags.recursion_desired = False;
773 p.packet.nmb.header.nm_flags.trunc = False;
774 p.packet.nmb.header.nm_flags.authoritative = False;
775 p.packet.nmb.header.rcode = 0;
776 p.packet.nmb.header.qdcount = 1;
777 p.packet.nmb.header.ancount = 0;
778 p.packet.nmb.header.nscount = 0;
779 p.packet.nmb.header.arcount = 0;
780 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
781 p.packet.nmb.question.question_type = 0x21;
782 p.packet.nmb.question.question_class = 0x1;
784 return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
787 /* A list of message type supported */
789 static const struct {
790 const char *name; /* Option name */
791 BOOL (*fn)(const struct process_id pid,
792 const int argc, const char **argv);
793 const char *help; /* Short help text */
795 { "debug", do_debug, "Set debuglevel" },
796 { "force-election", do_election,
797 "Force a browse election" },
798 { "ping", do_ping, "Elicit a response" },
799 { "profile", do_profile, "" },
800 { "inject", do_inject_fault,
801 "Inject a fatal signal into a running smbd"},
802 { "profilelevel", do_profilelevel, "" },
803 { "debuglevel", do_debuglevel, "Display current debuglevels" },
804 { "printnotify", do_printnotify, "Send a print notify message" },
805 { "close-share", do_closeshare, "Forcibly disconnect a share" },
806 { "samsync", do_samsync, "Initiate SAM synchronisation" },
807 { "samrepl", do_samrepl, "Initiate SAM replication" },
808 { "pool-usage", do_poolusage, "Display talloc memory usage" },
809 { "dmalloc-mark", do_dmalloc_mark, "" },
810 { "dmalloc-log-changed", do_dmalloc_changed, "" },
811 { "shutdown", do_shutdown, "Shut down daemon" },
812 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
813 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
814 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
815 { "online", do_winbind_online, "Ask winbind to go into online state"},
816 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
817 { "noop", do_noop, "Do nothing" },
821 /* Display usage information */
823 static void usage(poptContext *pc)
827 poptPrintHelp(*pc, stderr, 0);
829 fprintf(stderr, "\n");
830 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
833 fprintf(stderr, "\n");
834 fprintf(stderr, "<message-type> is one of:\n");
836 for (i = 0; msg_types[i].name; i++)
837 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
840 fprintf(stderr, "\n");
845 /* Return the pid number for a string destination */
847 static struct process_id parse_dest(const char *dest)
849 struct process_id result;
852 /* Zero is a special return value for broadcast smbd */
854 if (strequal(dest, "smbd")) {
855 return interpret_pid("0");
858 /* Try self - useful for testing */
860 if (strequal(dest, "self")) {
861 return pid_to_procid(sys_getpid());
864 /* Fix winbind typo. */
865 if (strequal(dest, "winbind")) {
870 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
871 /* Check for numeric pid number */
873 result = interpret_pid(dest);
875 /* Zero isn't valid if not smbd. */
876 if (result.pid && procid_valid(&result)) {
881 /* Look up other destinations in pidfile directory */
883 if ((pid = pidfile_pid(dest)) != 0) {
884 return pid_to_procid(pid);
887 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
892 /* Execute smbcontrol command */
894 static BOOL do_command(int argc, const char **argv)
896 const char *dest = argv[0], *command = argv[1];
897 struct process_id pid;
900 /* Check destination */
902 pid = parse_dest(dest);
903 if (!procid_valid(&pid)) {
909 for (i = 0; msg_types[i].name; i++) {
910 if (strequal(command, msg_types[i].name))
911 return msg_types[i].fn(pid, argc - 1, argv + 1);
914 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
921 int main(int argc, const char **argv)
926 static struct poptOption wbinfo_options[] = {
927 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
928 "Set timeout value in seconds", "TIMEOUT" },
930 { "configfile", 's', POPT_ARG_STRING, NULL, 's',
931 "Use alternative configuration file", "CONFIGFILE" },
936 struct poptOption options[] = {
937 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0,
947 setup_logging(argv[0],True);
949 /* Parse command line arguments using popt */
952 "smbcontrol", argc, (const char **)argv, options, 0);
954 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
960 while ((opt = poptGetNextOpt(pc)) != -1) {
962 case 't': /* --timeout */
965 case 's': /* --configfile */
966 pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
970 fprintf(stderr, "Invalid option\n");
971 poptPrintHelp(pc, stderr, 0);
976 /* We should now have the remaining command line arguments in
977 argv. The argc parameter should have been decremented to the
978 correct value in the above switch statement. */
980 argv = (const char **)poptGetArgs(pc);
981 argc--; /* Don't forget about argv[0] */
986 lp_load(dyn_CONFIGFILE,False,False,False,True);
988 /* Need to invert sense of return code -- samba
989 * routines mostly return True==1 for success, but
992 return !do_command(argc, argv);