Workaround for KB932762
[Samba.git] / source / utils / smbcontrol.c
blob060079a57351e65d906e196d8a47508bc046005f
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 NT_STATUS_IS_OK(message_send_pid(pid, msg_type, buf, len,
63 duplicates));
65 tdb = tdb_open_log(lock_path("connections.tdb"), 0,
66 TDB_DEFAULT, O_RDWR, 0);
67 if (!tdb) {
68 fprintf(stderr,"Failed to open connections database"
69 ": %s\n", strerror(errno));
70 return False;
73 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
74 &n_sent);
75 DEBUG(10,("smbcontrol/send_message: broadcast message to "
76 "%d processes\n", n_sent));
78 tdb_close(tdb);
80 return ret;
83 /* Wait for one or more reply messages */
85 static void wait_replies(BOOL multiple_replies)
87 time_t start_time = time(NULL);
89 /* Wait around a bit. This is pretty disgusting - we have to
90 busy-wait here as there is no nicer way to do it. */
92 do {
93 message_dispatch();
94 if (num_replies > 0 && !multiple_replies)
95 break;
96 sleep(1);
97 } while (timeout - (time(NULL) - start_time) > 0);
100 /* Message handler callback that displays the PID and a string on stdout */
102 static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf,
103 size_t len, void *private_data)
105 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
106 (int)len, (const char *)buf);
107 num_replies++;
110 /* Message handler callback that displays a string on stdout */
112 static void print_string_cb(int msg_type, struct process_id pid,
113 void *buf, size_t len, void *private_data)
115 printf("%.*s", (int)len, (const char *)buf);
116 num_replies++;
119 /* Send no message. Useful for testing. */
121 static BOOL do_noop(const struct process_id pid,
122 const int argc, const char **argv)
124 if (argc != 1) {
125 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
126 return False;
129 /* Move along, nothing to see here */
131 return True;
134 /* Send a debug string */
136 static BOOL do_debug(const struct process_id pid,
137 const int argc, const char **argv)
139 if (argc != 2) {
140 fprintf(stderr, "Usage: smbcontrol <dest> debug "
141 "<debug-string>\n");
142 return False;
145 return send_message(
146 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
149 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
151 /* Return the name of a process given it's PID. This will only work on Linux,
152 * but that's probably moot since this whole stack tracing implementatino is
153 * Linux-specific anyway.
155 static const char * procname(pid_t pid, char * buf, size_t bufsz)
157 char path[64];
158 FILE * fp;
160 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
161 (unsigned long long)pid);
162 if ((fp = fopen(path, "r")) == NULL) {
163 return NULL;
166 fgets(buf, bufsz, fp);
168 fclose(fp);
169 return buf;
172 static void print_stack_trace(pid_t pid, int * count)
174 void * pinfo = NULL;
175 unw_addr_space_t aspace = NULL;
176 unw_cursor_t cursor;
177 unw_word_t ip, sp;
179 char nbuf[256];
180 unw_word_t off;
182 int ret;
184 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
185 fprintf(stderr,
186 "Failed to attach to process %llu: %s\n",
187 (unsigned long long)pid, strerror(errno));
188 return;
191 /* Wait until the attach is complete. */
192 waitpid(pid, NULL, 0);
194 if (((pinfo = _UPT_create(pid)) == NULL) ||
195 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
196 /* Probably out of memory. */
197 fprintf(stderr,
198 "Unable to initialize stack unwind for process %llu\n",
199 (unsigned long long)pid);
200 goto cleanup;
203 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
204 fprintf(stderr,
205 "Unable to unwind stack for process %llu: %s\n",
206 (unsigned long long)pid, unw_strerror(ret));
207 goto cleanup;
210 if (*count > 0) {
211 printf("\n");
214 if (procname(pid, nbuf, sizeof(nbuf))) {
215 printf("Stack trace for process %llu (%s):\n",
216 (unsigned long long)pid, nbuf);
217 } else {
218 printf("Stack trace for process %llu:\n",
219 (unsigned long long)pid);
222 while (unw_step(&cursor) > 0) {
223 ip = sp = off = 0;
224 unw_get_reg(&cursor, UNW_REG_IP, &ip);
225 unw_get_reg(&cursor, UNW_REG_SP, &sp);
227 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
228 if (ret != 0 && ret != -UNW_ENOMEM) {
229 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
231 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
232 nbuf, (long long)off, (long long)ip,
233 (long long)sp);
236 (*count)++;
238 cleanup:
239 if (aspace) {
240 unw_destroy_addr_space(aspace);
243 if (pinfo) {
244 _UPT_destroy(pinfo);
247 ptrace(PTRACE_DETACH, pid, NULL, NULL);
250 static int stack_trace_connection(TDB_CONTEXT * tdb, TDB_DATA key,
251 TDB_DATA data, void * priv)
253 struct connections_data conn;
255 if (data.dsize != sizeof(conn))
256 return 0;
258 memcpy(&conn, data.dptr, sizeof(conn));
259 print_stack_trace(procid_to_pid(&conn.pid), (int *)priv);
261 return 0;
264 static BOOL do_daemon_stack_trace(const struct process_id pid,
265 const int argc, const char **argv)
267 fprintf(stderr,
268 "Daemon stack tracing is not supported on this platform\n");
269 return False;
271 pid_t dest;
272 int count = 0;
274 if (argc != 1) {
275 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
276 return False;
279 dest = procid_to_pid(&pid);
281 if (dest != 0) {
282 /* It would be nice to be able to make sure that this PID is
283 * the PID of a smbd/winbind/nmbd process, not some random PID
284 * the user liked the look of. It doesn't seem like it's worth
285 * the effort at the moment, however.
287 print_stack_trace(dest, &count);
288 } else {
289 TDB_CONTEXT * tdb;
291 tdb = tdb_open_log(lock_path("connections.tdb"), 0,
292 TDB_DEFAULT, O_RDONLY, 0);
293 if (!tdb) {
294 fprintf(stderr,
295 "Failed to open connections database: %s\n",
296 strerror(errno));
297 return False;
300 tdb_traverse(tdb, stack_trace_connection, &count);
301 tdb_close(tdb);
304 return True;
307 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
309 static BOOL do_daemon_stack_trace(const struct process_id pid,
310 const int argc, const char **argv)
312 fprintf(stderr,
313 "Daemon stack tracing is not supported on this platform\n");
314 return False;
317 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
319 /* Inject a fault (fatal signal) into a running smbd */
321 static BOOL do_inject_fault(const struct process_id pid,
322 const int argc, const char **argv)
324 if (argc != 2) {
325 fprintf(stderr, "Usage: smbcontrol <dest> inject "
326 "<bus|hup|term|internal|segv>\n");
327 return False;
330 #ifndef DEVELOPER
331 fprintf(stderr, "Fault injection is only available in "
332 "developer builds\n");
333 return False;
334 #else /* DEVELOPER */
336 int sig = 0;
338 if (strcmp(argv[1], "bus") == 0) {
339 sig = SIGBUS;
340 } else if (strcmp(argv[1], "hup") == 0) {
341 sig = SIGHUP;
342 } else if (strcmp(argv[1], "term") == 0) {
343 sig = SIGTERM;
344 } else if (strcmp(argv[1], "segv") == 0) {
345 sig = SIGSEGV;
346 } else if (strcmp(argv[1], "internal") == 0) {
347 /* Force an internal error, ie. an unclean exit. */
348 sig = -1;
349 } else {
350 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
351 return False;
354 return send_message(pid, MSG_SMB_INJECT_FAULT,
355 &sig, sizeof(int), False);
357 #endif /* DEVELOPER */
360 /* Force a browser election */
362 static BOOL do_election(const struct process_id pid,
363 const int argc, const char **argv)
365 if (argc != 1) {
366 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
367 return False;
370 return send_message(
371 pid, MSG_FORCE_ELECTION, NULL, 0, False);
374 /* Ping a samba daemon process */
376 static void pong_cb(int msg_type, struct process_id pid, void *buf,
377 size_t len, void *private_data)
379 char *src_string = procid_str(NULL, &pid);
380 printf("PONG from pid %s\n", src_string);
381 TALLOC_FREE(src_string);
382 num_replies++;
385 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
387 if (argc != 1) {
388 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
389 return False;
392 /* Send a message and register our interest in a reply */
394 if (!send_message(pid, MSG_PING, NULL, 0, False))
395 return False;
397 message_register(MSG_PONG, pong_cb, NULL);
399 wait_replies(procid_to_pid(&pid) == 0);
401 /* No replies were received within the timeout period */
403 if (num_replies == 0)
404 printf("No replies received\n");
406 message_deregister(MSG_PONG);
408 return num_replies;
411 /* Set profiling options */
413 static BOOL do_profile(const struct process_id pid,
414 const int argc, const char **argv)
416 int v;
418 if (argc != 2) {
419 fprintf(stderr, "Usage: smbcontrol <dest> profile "
420 "<off|count|on|flush>\n");
421 return False;
424 if (strcmp(argv[1], "off") == 0) {
425 v = 0;
426 } else if (strcmp(argv[1], "count") == 0) {
427 v = 1;
428 } else if (strcmp(argv[1], "on") == 0) {
429 v = 2;
430 } else if (strcmp(argv[1], "flush") == 0) {
431 v = 3;
432 } else {
433 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
434 return False;
437 return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
440 /* Return the profiling level */
442 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf,
443 size_t len, void *private_data)
445 int level;
446 const char *s;
448 num_replies++;
450 if (len != sizeof(int)) {
451 fprintf(stderr, "invalid message length %ld returned\n",
452 (unsigned long)len);
453 return;
456 memcpy(&level, buf, sizeof(int));
458 switch (level) {
459 case 0:
460 s = "not enabled";
461 break;
462 case 1:
463 s = "off";
464 break;
465 case 3:
466 s = "count only";
467 break;
468 case 7:
469 s = "count and time";
470 break;
471 default:
472 s = "BOGUS";
473 break;
476 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
479 static void profilelevel_rqst(int msg_type, struct process_id pid,
480 void *buf, size_t len, void *private_data)
482 int v = 0;
484 /* Send back a dummy reply */
486 send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
489 static BOOL do_profilelevel(const struct process_id pid,
490 const int argc, const char **argv)
492 if (argc != 1) {
493 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
494 return False;
497 /* Send a message and register our interest in a reply */
499 if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
500 return False;
502 message_register(MSG_PROFILELEVEL, profilelevel_cb, NULL);
503 message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst, NULL);
505 wait_replies(procid_to_pid(&pid) == 0);
507 /* No replies were received within the timeout period */
509 if (num_replies == 0)
510 printf("No replies received\n");
512 message_deregister(MSG_PROFILE);
514 return num_replies;
517 /* Display debug level settings */
519 static BOOL do_debuglevel(const struct process_id pid,
520 const int argc, const char **argv)
522 if (argc != 1) {
523 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
524 return False;
527 /* Send a message and register our interest in a reply */
529 if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
530 return False;
532 message_register(MSG_DEBUGLEVEL, print_pid_string_cb, NULL);
534 wait_replies(procid_to_pid(&pid) == 0);
536 /* No replies were received within the timeout period */
538 if (num_replies == 0)
539 printf("No replies received\n");
541 message_deregister(MSG_DEBUGLEVEL);
543 return num_replies;
546 /* Send a print notify message */
548 static BOOL do_printnotify(const struct process_id pid,
549 const int argc, const char **argv)
551 const char *cmd;
553 /* Check for subcommand */
555 if (argc == 1) {
556 fprintf(stderr, "Must specify subcommand:\n");
557 fprintf(stderr, "\tqueuepause <printername>\n");
558 fprintf(stderr, "\tqueueresume <printername>\n");
559 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
560 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
561 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
562 fprintf(stderr, "\tprinter <printername> <comment|port|"
563 "driver> <value>\n");
565 return False;
568 cmd = argv[1];
570 if (strcmp(cmd, "queuepause") == 0) {
572 if (argc != 3) {
573 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
574 " queuepause <printername>\n");
575 return False;
578 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
580 goto send;
582 } else if (strcmp(cmd, "queueresume") == 0) {
584 if (argc != 3) {
585 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
586 " queuereume <printername>\n");
587 return False;
590 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
592 goto send;
594 } else if (strcmp(cmd, "jobpause") == 0) {
595 int jobid;
597 if (argc != 4) {
598 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
599 " jobpause <printername> <unix-jobid>\n");
600 return False;
603 jobid = atoi(argv[3]);
605 notify_job_status_byname(
606 argv[2], jobid, JOB_STATUS_PAUSED,
607 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
609 goto send;
611 } else if (strcmp(cmd, "jobresume") == 0) {
612 int jobid;
614 if (argc != 4) {
615 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
616 " jobpause <printername> <unix-jobid>\n");
617 return False;
620 jobid = atoi(argv[3]);
622 notify_job_status_byname(
623 argv[2], jobid, JOB_STATUS_QUEUED,
624 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
626 goto send;
628 } else if (strcmp(cmd, "jobdelete") == 0) {
629 int jobid;
631 if (argc != 4) {
632 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
633 " jobpause <printername> <unix-jobid>\n");
634 return False;
637 jobid = atoi(argv[3]);
639 notify_job_status_byname(
640 argv[2], jobid, JOB_STATUS_DELETING,
641 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
643 notify_job_status_byname(
644 argv[2], jobid, JOB_STATUS_DELETING|
645 JOB_STATUS_DELETED,
646 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
648 goto send;
650 } else if (strcmp(cmd, "printer") == 0) {
651 uint32 attribute;
653 if (argc != 5) {
654 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
655 "printer <printername> <comment|port|driver> "
656 "<value>\n");
657 return False;
660 if (strcmp(argv[3], "comment") == 0) {
661 attribute = PRINTER_NOTIFY_COMMENT;
662 } else if (strcmp(argv[3], "port") == 0) {
663 attribute = PRINTER_NOTIFY_PORT_NAME;
664 } else if (strcmp(argv[3], "driver") == 0) {
665 attribute = PRINTER_NOTIFY_DRIVER_NAME;
666 } else {
667 fprintf(stderr, "Invalid printer command '%s'\n",
668 argv[3]);
669 return False;
672 notify_printer_byname(argv[2], attribute,
673 CONST_DISCARD(char *, argv[4]));
675 goto send;
678 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
679 return False;
681 send:
682 print_notify_send_messages(0);
683 return True;
686 /* Close a share */
688 static BOOL do_closeshare(const struct process_id pid,
689 const int argc, const char **argv)
691 if (argc != 2) {
692 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
693 "<sharename>\n");
694 return False;
697 return send_message(
698 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
701 /* Force a SAM synchronisation */
703 static BOOL do_samsync(const struct process_id pid,
704 const int argc, const char **argv)
706 if (argc != 1) {
707 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
708 return False;
711 return send_message(
712 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
715 /* Force a SAM replication */
717 static BOOL do_samrepl(const struct process_id pid,
718 const int argc, const char **argv)
720 if (argc != 1) {
721 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
722 return False;
725 return send_message(
726 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
729 /* Display talloc pool usage */
731 static BOOL do_poolusage(const struct process_id pid,
732 const int argc, const char **argv)
734 if (argc != 1) {
735 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
736 return False;
739 message_register(MSG_POOL_USAGE, print_string_cb, NULL);
741 /* Send a message and register our interest in a reply */
743 if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
744 return False;
746 wait_replies(procid_to_pid(&pid) == 0);
748 /* No replies were received within the timeout period */
750 if (num_replies == 0)
751 printf("No replies received\n");
753 message_deregister(MSG_POOL_USAGE);
755 return num_replies;
758 /* Perform a dmalloc mark */
760 static BOOL do_dmalloc_mark(const struct process_id pid,
761 const int argc, const char **argv)
763 if (argc != 1) {
764 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
765 return False;
768 return send_message(
769 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
772 /* Perform a dmalloc changed */
774 static BOOL do_dmalloc_changed(const struct process_id pid,
775 const int argc, const char **argv)
777 if (argc != 1) {
778 fprintf(stderr, "Usage: smbcontrol <dest> "
779 "dmalloc-log-changed\n");
780 return False;
783 return send_message(
784 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
787 /* Shutdown a server process */
789 static BOOL do_shutdown(const struct process_id pid,
790 const int argc, const char **argv)
792 if (argc != 1) {
793 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
794 return False;
797 return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
800 /* Notify a driver upgrade */
802 static BOOL do_drvupgrade(const struct process_id pid,
803 const int argc, const char **argv)
805 if (argc != 2) {
806 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
807 "<driver-name>\n");
808 return False;
811 return send_message(
812 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
815 static BOOL do_winbind_online(const struct process_id pid,
816 const int argc, const char **argv)
818 TDB_CONTEXT *tdb;
820 if (argc != 1) {
821 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
822 return False;
825 if (!lp_winbind_offline_logon()) {
826 fprintf(stderr, "The parameter \"winbind offline logon\" must "
827 "be set in the [global] section of smb.conf for this "
828 "command to be allowed.\n");
829 return False;
832 /* Remove the entry in the winbindd_cache tdb to tell a later
833 starting winbindd that we're online. */
835 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
836 if (!tdb) {
837 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
838 lock_path("winbindd_cache.tdb"));
839 return False;
842 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
843 tdb_close(tdb);
845 return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
848 static BOOL do_winbind_offline(const struct process_id pid,
849 const int argc, const char **argv)
851 TDB_CONTEXT *tdb;
852 BOOL ret = False;
853 int retry = 0;
855 if (argc != 1) {
856 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
857 return False;
860 if (!lp_winbind_offline_logon()) {
861 fprintf(stderr, "The parameter \"winbind offline logon\" must "
862 "be set in the [global] section of smb.conf for this "
863 "command to be allowed.\n");
864 return False;
867 /* Create an entry in the winbindd_cache tdb to tell a later
868 starting winbindd that we're offline. We may actually create
869 it here... */
871 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
872 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
873 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
875 if (!tdb) {
876 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
877 lock_path("winbindd_cache.tdb"));
878 return False;
881 /* There's a potential race condition that if a child
882 winbindd detects a domain is online at the same time
883 we're trying to tell it to go offline that it might
884 delete the record we add between us adding it and
885 sending the message. Minimize this by retrying up to
886 5 times. */
888 for (retry = 0; retry < 5; retry++) {
889 TDB_DATA d;
890 char buf[4];
892 ZERO_STRUCT(d);
894 SIVAL(buf, 0, time(NULL));
895 d.dptr = buf;
896 d.dsize = 4;
898 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
900 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
902 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
903 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
905 if (!d.dptr || d.dsize != 4) {
906 SAFE_FREE(d.dptr);
907 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
908 } else {
909 SAFE_FREE(d.dptr);
910 break;
914 tdb_close(tdb);
915 return ret;
918 static BOOL do_winbind_onlinestatus(const struct process_id pid,
919 const int argc, const char **argv)
921 struct process_id myid;
923 myid = pid_to_procid(sys_getpid());
925 if (argc != 1) {
926 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
927 return False;
930 message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb, NULL);
932 if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False))
933 return False;
935 wait_replies(procid_to_pid(&pid) == 0);
937 /* No replies were received within the timeout period */
939 if (num_replies == 0)
940 printf("No replies received\n");
942 message_deregister(MSG_WINBIND_ONLINESTATUS);
944 return num_replies;
948 static BOOL do_reload_config(const struct process_id pid,
949 const int argc, const char **argv)
951 if (argc != 1) {
952 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
953 return False;
956 return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
959 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
961 fstring unix_name;
962 memset( (char *)n, '\0', sizeof(struct nmb_name) );
963 fstrcpy(unix_name, name);
964 strupper_m(unix_name);
965 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
966 n->name_type = (unsigned int)type & 0xFF;
967 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
970 static BOOL do_nodestatus(const struct process_id pid,
971 const int argc, const char **argv)
973 struct packet_struct p;
975 if (argc != 2) {
976 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
977 return False;
980 ZERO_STRUCT(p);
982 p.ip = *interpret_addr2(argv[1]);
983 p.port = 137;
984 p.packet_type = NMB_PACKET;
986 p.packet.nmb.header.name_trn_id = 10;
987 p.packet.nmb.header.opcode = 0;
988 p.packet.nmb.header.response = False;
989 p.packet.nmb.header.nm_flags.bcast = False;
990 p.packet.nmb.header.nm_flags.recursion_available = False;
991 p.packet.nmb.header.nm_flags.recursion_desired = False;
992 p.packet.nmb.header.nm_flags.trunc = False;
993 p.packet.nmb.header.nm_flags.authoritative = False;
994 p.packet.nmb.header.rcode = 0;
995 p.packet.nmb.header.qdcount = 1;
996 p.packet.nmb.header.ancount = 0;
997 p.packet.nmb.header.nscount = 0;
998 p.packet.nmb.header.arcount = 0;
999 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1000 p.packet.nmb.question.question_type = 0x21;
1001 p.packet.nmb.question.question_class = 0x1;
1003 return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
1006 /* A list of message type supported */
1008 static const struct {
1009 const char *name; /* Option name */
1010 BOOL (*fn)(const struct process_id pid,
1011 const int argc, const char **argv);
1012 const char *help; /* Short help text */
1013 } msg_types[] = {
1014 { "debug", do_debug, "Set debuglevel" },
1015 { "force-election", do_election,
1016 "Force a browse election" },
1017 { "ping", do_ping, "Elicit a response" },
1018 { "profile", do_profile, "" },
1019 { "inject", do_inject_fault,
1020 "Inject a fatal signal into a running smbd"},
1021 { "stacktrace", do_daemon_stack_trace,
1022 "Display a stack trace of a daemon" },
1023 { "profilelevel", do_profilelevel, "" },
1024 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1025 { "printnotify", do_printnotify, "Send a print notify message" },
1026 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1027 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1028 { "samrepl", do_samrepl, "Initiate SAM replication" },
1029 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1030 { "dmalloc-mark", do_dmalloc_mark, "" },
1031 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1032 { "shutdown", do_shutdown, "Shut down daemon" },
1033 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1034 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1035 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1036 { "online", do_winbind_online, "Ask winbind to go into online state"},
1037 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1038 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1039 { "noop", do_noop, "Do nothing" },
1040 { NULL }
1043 /* Display usage information */
1045 static void usage(poptContext *pc)
1047 int i;
1049 poptPrintHelp(*pc, stderr, 0);
1051 fprintf(stderr, "\n");
1052 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1053 "process ID\n");
1055 fprintf(stderr, "\n");
1056 fprintf(stderr, "<message-type> is one of:\n");
1058 for (i = 0; msg_types[i].name; i++)
1059 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1060 msg_types[i].help);
1062 fprintf(stderr, "\n");
1064 exit(1);
1067 /* Return the pid number for a string destination */
1069 static struct process_id parse_dest(const char *dest)
1071 struct process_id result = {-1};
1072 pid_t pid;
1074 /* Zero is a special return value for broadcast smbd */
1076 if (strequal(dest, "smbd")) {
1077 return interpret_pid("0");
1080 /* Try self - useful for testing */
1082 if (strequal(dest, "self")) {
1083 return pid_to_procid(sys_getpid());
1086 /* Fix winbind typo. */
1087 if (strequal(dest, "winbind")) {
1088 dest = "winbindd";
1092 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1093 /* Check for numeric pid number */
1095 result = interpret_pid(dest);
1097 /* Zero isn't valid if not smbd. */
1098 if (result.pid && procid_valid(&result)) {
1099 return result;
1103 /* Look up other destinations in pidfile directory */
1105 if ((pid = pidfile_pid(dest)) != 0) {
1106 return pid_to_procid(pid);
1109 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1111 return result;
1114 /* Execute smbcontrol command */
1116 static BOOL do_command(int argc, const char **argv)
1118 const char *dest = argv[0], *command = argv[1];
1119 struct process_id pid;
1120 int i;
1122 /* Check destination */
1124 pid = parse_dest(dest);
1125 if (!procid_valid(&pid)) {
1126 return False;
1129 /* Check command */
1131 for (i = 0; msg_types[i].name; i++) {
1132 if (strequal(command, msg_types[i].name))
1133 return msg_types[i].fn(pid, argc - 1, argv + 1);
1136 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1138 return False;
1141 /* Main program */
1143 int main(int argc, const char **argv)
1145 poptContext pc;
1146 int opt;
1148 static struct poptOption long_options[] = {
1149 POPT_AUTOHELP
1150 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1151 "Set timeout value in seconds", "TIMEOUT" },
1153 POPT_COMMON_SAMBA
1154 POPT_TABLEEND
1157 load_case_tables();
1159 setup_logging(argv[0],True);
1161 /* Parse command line arguments using popt */
1163 pc = poptGetContext(
1164 "smbcontrol", argc, (const char **)argv, long_options, 0);
1166 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1167 "<parameters>");
1169 if (argc == 1)
1170 usage(&pc);
1172 while ((opt = poptGetNextOpt(pc)) != -1) {
1173 switch(opt) {
1174 case 't': /* --timeout */
1175 break;
1176 default:
1177 fprintf(stderr, "Invalid option\n");
1178 poptPrintHelp(pc, stderr, 0);
1179 break;
1183 /* We should now have the remaining command line arguments in
1184 argv. The argc parameter should have been decremented to the
1185 correct value in the above switch statement. */
1187 argv = (const char **)poptGetArgs(pc);
1188 argc = 0;
1189 while (argv[argc] != NULL) {
1190 argc++;
1193 if (argc == 1)
1194 usage(&pc);
1196 lp_load(dyn_CONFIGFILE,False,False,False,True);
1198 /* Need to invert sense of return code -- samba
1199 * routines mostly return True==1 for success, but
1200 * shell needs 0. */
1202 return !do_command(argc, argv);