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 /* Force a browser election */
136 static BOOL do_election(const struct process_id pid,
137 const int argc, const char **argv)
140 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
145 pid, MSG_FORCE_ELECTION, NULL, 0, False);
148 /* Ping a samba daemon process */
150 static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len)
152 char *src_string = procid_str(NULL, &pid);
153 printf("PONG from pid %s\n", src_string);
154 TALLOC_FREE(src_string);
158 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
161 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
165 /* Send a message and register our interest in a reply */
167 if (!send_message(pid, MSG_PING, NULL, 0, False))
170 message_register(MSG_PONG, pong_cb);
172 wait_replies(procid_to_pid(&pid) == 0);
174 /* No replies were received within the timeout period */
176 if (num_replies == 0)
177 printf("No replies received\n");
179 message_deregister(MSG_PONG);
184 /* Set profiling options */
186 static BOOL do_profile(const struct process_id pid,
187 const int argc, const char **argv)
192 fprintf(stderr, "Usage: smbcontrol <dest> profile "
193 "<off|count|on|flush>\n");
197 if (strcmp(argv[1], "off") == 0) {
199 } else if (strcmp(argv[1], "count") == 0) {
201 } else if (strcmp(argv[1], "on") == 0) {
203 } else if (strcmp(argv[1], "flush") == 0) {
206 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
210 return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
213 /* Return the profiling level */
215 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len)
222 if (len != sizeof(int)) {
223 fprintf(stderr, "invalid message length %ld returned\n",
228 memcpy(&level, buf, sizeof(int));
241 s = "count and time";
248 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
251 static void profilelevel_rqst(int msg_type, struct process_id pid,
252 void *buf, size_t len)
256 /* Send back a dummy reply */
258 send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
261 static BOOL do_profilelevel(const struct process_id pid,
262 const int argc, const char **argv)
265 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
269 /* Send a message and register our interest in a reply */
271 if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
274 message_register(MSG_PROFILELEVEL, profilelevel_cb);
275 message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
277 wait_replies(procid_to_pid(&pid) == 0);
279 /* No replies were received within the timeout period */
281 if (num_replies == 0)
282 printf("No replies received\n");
284 message_deregister(MSG_PROFILE);
289 /* Display debug level settings */
291 static BOOL do_debuglevel(const struct process_id pid,
292 const int argc, const char **argv)
295 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
299 /* Send a message and register our interest in a reply */
301 if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
304 message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
306 wait_replies(procid_to_pid(&pid) == 0);
308 /* No replies were received within the timeout period */
310 if (num_replies == 0)
311 printf("No replies received\n");
313 message_deregister(MSG_DEBUGLEVEL);
318 /* Send a print notify message */
320 static BOOL do_printnotify(const struct process_id pid,
321 const int argc, const char **argv)
325 /* Check for subcommand */
328 fprintf(stderr, "Must specify subcommand:\n");
329 fprintf(stderr, "\tqueuepause <printername>\n");
330 fprintf(stderr, "\tqueueresume <printername>\n");
331 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
332 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
333 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
334 fprintf(stderr, "\tprinter <printername> <comment|port|"
335 "driver> <value>\n");
342 if (strcmp(cmd, "queuepause") == 0) {
345 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
346 " queuepause <printername>\n");
350 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
354 } else if (strcmp(cmd, "queueresume") == 0) {
357 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
358 " queuereume <printername>\n");
362 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
366 } else if (strcmp(cmd, "jobpause") == 0) {
370 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
371 " jobpause <printername> <unix-jobid>\n");
375 jobid = atoi(argv[3]);
377 notify_job_status_byname(
378 argv[2], jobid, JOB_STATUS_PAUSED,
379 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
383 } else if (strcmp(cmd, "jobresume") == 0) {
387 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
388 " jobpause <printername> <unix-jobid>\n");
392 jobid = atoi(argv[3]);
394 notify_job_status_byname(
395 argv[2], jobid, JOB_STATUS_QUEUED,
396 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
400 } else if (strcmp(cmd, "jobdelete") == 0) {
404 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
405 " jobpause <printername> <unix-jobid>\n");
409 jobid = atoi(argv[3]);
411 notify_job_status_byname(
412 argv[2], jobid, JOB_STATUS_DELETING,
413 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
415 notify_job_status_byname(
416 argv[2], jobid, JOB_STATUS_DELETING|
418 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
422 } else if (strcmp(cmd, "printer") == 0) {
426 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
427 "printer <printername> <comment|port|driver> "
432 if (strcmp(argv[3], "comment") == 0) {
433 attribute = PRINTER_NOTIFY_COMMENT;
434 } else if (strcmp(argv[3], "port") == 0) {
435 attribute = PRINTER_NOTIFY_PORT_NAME;
436 } else if (strcmp(argv[3], "driver") == 0) {
437 attribute = PRINTER_NOTIFY_DRIVER_NAME;
439 fprintf(stderr, "Invalid printer command '%s'\n",
444 notify_printer_byname(argv[2], attribute,
445 CONST_DISCARD(char *, argv[4]));
450 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
454 print_notify_send_messages(0);
460 static BOOL do_closeshare(const struct process_id pid,
461 const int argc, const char **argv)
464 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
470 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
473 /* Force a SAM synchronisation */
475 static BOOL do_samsync(const struct process_id pid,
476 const int argc, const char **argv)
479 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
484 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
487 /* Force a SAM replication */
489 static BOOL do_samrepl(const struct process_id pid,
490 const int argc, const char **argv)
493 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
498 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
501 /* Display talloc pool usage */
503 static BOOL do_poolusage(const struct process_id pid,
504 const int argc, const char **argv)
507 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
511 message_register(MSG_POOL_USAGE, print_string_cb);
513 /* Send a message and register our interest in a reply */
515 if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
518 wait_replies(procid_to_pid(&pid) == 0);
520 /* No replies were received within the timeout period */
522 if (num_replies == 0)
523 printf("No replies received\n");
525 message_deregister(MSG_POOL_USAGE);
530 /* Perform a dmalloc mark */
532 static BOOL do_dmalloc_mark(const struct process_id pid,
533 const int argc, const char **argv)
536 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
541 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
544 /* Perform a dmalloc changed */
546 static BOOL do_dmalloc_changed(const struct process_id pid,
547 const int argc, const char **argv)
550 fprintf(stderr, "Usage: smbcontrol <dest> "
551 "dmalloc-log-changed\n");
556 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
559 /* Shutdown a server process */
561 static BOOL do_shutdown(const struct process_id pid,
562 const int argc, const char **argv)
565 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
569 return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
572 /* Notify a driver upgrade */
574 static BOOL do_drvupgrade(const struct process_id pid,
575 const int argc, const char **argv)
578 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
584 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
587 static BOOL do_winbind_online(const struct process_id pid,
588 const int argc, const char **argv)
593 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
597 if (!lp_winbind_offline_logon()) {
598 fprintf(stderr, "The parameter \"winbind offline logon\" must "
599 "be set in the [global] section of smb.conf for this "
600 "command to be allowed.\n");
604 /* Remove the entry in the winbindd_cache tdb to tell a later
605 starting winbindd that we're online. */
607 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
609 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
610 lock_path("winbindd_cache.tdb"));
614 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
617 return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
620 static BOOL do_winbind_offline(const struct process_id pid,
621 const int argc, const char **argv)
628 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
632 if (!lp_winbind_offline_logon()) {
633 fprintf(stderr, "The parameter \"winbind offline logon\" must "
634 "be set in the [global] section of smb.conf for this "
635 "command to be allowed.\n");
639 /* Create an entry in the winbindd_cache tdb to tell a later
640 starting winbindd that we're offline. We may actually create
643 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
644 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
645 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
648 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
649 lock_path("winbindd_cache.tdb"));
653 /* There's a potential race condition that if a child
654 winbindd detects a domain is online at the same time
655 we're trying to tell it to go offline that it might
656 delete the record we add between us adding it and
657 sending the message. Minimize this by retrying up to
660 for (retry = 0; retry < 5; retry++) {
664 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
666 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
668 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
670 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
672 /* As this is a key with no data we don't need to free, we
673 check for existence by looking at tdb_err. */
675 err = tdb_error(tdb);
677 if (err == TDB_ERR_NOEXIST) {
678 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
688 static BOOL do_reload_config(const struct process_id pid,
689 const int argc, const char **argv)
692 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
696 return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
699 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
702 memset( (char *)n, '\0', sizeof(struct nmb_name) );
703 fstrcpy(unix_name, name);
704 strupper_m(unix_name);
705 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
706 n->name_type = (unsigned int)type & 0xFF;
707 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
710 static BOOL do_nodestatus(const struct process_id pid,
711 const int argc, const char **argv)
713 struct packet_struct p;
716 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
722 p.ip = *interpret_addr2(argv[1]);
724 p.packet_type = NMB_PACKET;
726 p.packet.nmb.header.name_trn_id = 10;
727 p.packet.nmb.header.opcode = 0;
728 p.packet.nmb.header.response = False;
729 p.packet.nmb.header.nm_flags.bcast = False;
730 p.packet.nmb.header.nm_flags.recursion_available = False;
731 p.packet.nmb.header.nm_flags.recursion_desired = False;
732 p.packet.nmb.header.nm_flags.trunc = False;
733 p.packet.nmb.header.nm_flags.authoritative = False;
734 p.packet.nmb.header.rcode = 0;
735 p.packet.nmb.header.qdcount = 1;
736 p.packet.nmb.header.ancount = 0;
737 p.packet.nmb.header.nscount = 0;
738 p.packet.nmb.header.arcount = 0;
739 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
740 p.packet.nmb.question.question_type = 0x21;
741 p.packet.nmb.question.question_class = 0x1;
743 return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
746 /* A list of message type supported */
748 static const struct {
749 const char *name; /* Option name */
750 BOOL (*fn)(const struct process_id pid,
751 const int argc, const char **argv);
752 const char *help; /* Short help text */
754 { "debug", do_debug, "Set debuglevel" },
755 { "force-election", do_election,
756 "Force a browse election" },
757 { "ping", do_ping, "Elicit a response" },
758 { "profile", do_profile, "" },
759 { "profilelevel", do_profilelevel, "" },
760 { "debuglevel", do_debuglevel, "Display current debuglevels" },
761 { "printnotify", do_printnotify, "Send a print notify message" },
762 { "close-share", do_closeshare, "Forcibly disconnect a share" },
763 { "samsync", do_samsync, "Initiate SAM synchronisation" },
764 { "samrepl", do_samrepl, "Initiate SAM replication" },
765 { "pool-usage", do_poolusage, "Display talloc memory usage" },
766 { "dmalloc-mark", do_dmalloc_mark, "" },
767 { "dmalloc-log-changed", do_dmalloc_changed, "" },
768 { "shutdown", do_shutdown, "Shut down daemon" },
769 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
770 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
771 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
772 { "online", do_winbind_online, "Ask winbind to go into online state"},
773 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
774 { "noop", do_noop, "Do nothing" },
778 /* Display usage information */
780 static void usage(poptContext *pc)
784 poptPrintHelp(*pc, stderr, 0);
786 fprintf(stderr, "\n");
787 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
790 fprintf(stderr, "\n");
791 fprintf(stderr, "<message-type> is one of:\n");
793 for (i = 0; msg_types[i].name; i++)
794 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
797 fprintf(stderr, "\n");
802 /* Return the pid number for a string destination */
804 static struct process_id parse_dest(const char *dest)
806 struct process_id result;
809 /* Zero is a special return value for broadcast smbd */
811 if (strequal(dest, "smbd")) {
812 return interpret_pid("0");
815 /* Try self - useful for testing */
817 if (strequal(dest, "self")) {
818 return pid_to_procid(sys_getpid());
821 /* Fix winbind typo. */
822 if (strequal(dest, "winbind")) {
827 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
828 /* Check for numeric pid number */
830 result = interpret_pid(dest);
832 /* Zero isn't valid if not smbd. */
833 if (result.pid && procid_valid(&result)) {
838 /* Look up other destinations in pidfile directory */
840 if ((pid = pidfile_pid(dest)) != 0) {
841 return pid_to_procid(pid);
844 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
849 /* Execute smbcontrol command */
851 static BOOL do_command(int argc, const char **argv)
853 const char *dest = argv[0], *command = argv[1];
854 struct process_id pid;
857 /* Check destination */
859 pid = parse_dest(dest);
860 if (!procid_valid(&pid)) {
866 for (i = 0; msg_types[i].name; i++) {
867 if (strequal(command, msg_types[i].name))
868 return msg_types[i].fn(pid, argc - 1, argv + 1);
871 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
878 int main(int argc, const char **argv)
883 static struct poptOption wbinfo_options[] = {
884 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
885 "Set timeout value in seconds", "TIMEOUT" },
887 { "configfile", 's', POPT_ARG_STRING, NULL, 's',
888 "Use alternative configuration file", "CONFIGFILE" },
893 struct poptOption options[] = {
894 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0,
904 setup_logging(argv[0],True);
906 /* Parse command line arguments using popt */
909 "smbcontrol", argc, (const char **)argv, options, 0);
911 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
917 while ((opt = poptGetNextOpt(pc)) != -1) {
919 case 't': /* --timeout */
922 case 's': /* --configfile */
923 pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
927 fprintf(stderr, "Invalid option\n");
928 poptPrintHelp(pc, stderr, 0);
933 /* We should now have the remaining command line arguments in
934 argv. The argc parameter should have been decremented to the
935 correct value in the above switch statement. */
937 argv = (const char **)poptGetArgs(pc);
938 argc--; /* Don't forget about argv[0] */
943 lp_load(dyn_CONFIGFILE,False,False,False,True);
945 /* Need to invert sense of return code -- samba
946 * routines mostly return True==1 for success, but
949 return !do_command(argc, argv);