WHATSNEW: Update changes.
[Samba/gbeck.git] / source3 / utils / smbcontrol.c
blob7fab6eb4b26aae085db0af9b560fe49ae33ecde0
1 /*
2 Unix SMB/CIFS implementation.
4 Send messages to other Samba daemons
6 Copyright (C) Tim Potter 2003
7 Copyright (C) Andrew Tridgell 1994-1998
8 Copyright (C) Martin Pool 2001-2002
9 Copyright (C) Simo Sorce 2002
10 Copyright (C) James Peach 2006
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
28 #if HAVE_LIBUNWIND_H
29 #include <libunwind.h>
30 #endif
32 #if HAVE_LIBUNWIND_PTRACE_H
33 #include <libunwind-ptrace.h>
34 #endif
36 #if HAVE_SYS_PTRACE_H
37 #include <sys/ptrace.h>
38 #endif
40 /* Default timeout value when waiting for replies (in seconds) */
42 #define DEFAULT_TIMEOUT 10
44 static int timeout = DEFAULT_TIMEOUT;
45 static int num_replies; /* Used by message callback fns */
47 /* Send a message to a destination pid. Zero means broadcast smbd. */
49 static bool send_message(struct messaging_context *msg_ctx,
50 struct server_id pid, int msg_type,
51 const void *buf, int len)
53 bool ret;
54 int n_sent = 0;
56 if (procid_to_pid(&pid) != 0)
57 return NT_STATUS_IS_OK(
58 messaging_send_buf(msg_ctx, pid, msg_type,
59 (uint8 *)buf, len));
61 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
62 DEBUG(10,("smbcontrol/send_message: broadcast message to "
63 "%d processes\n", n_sent));
65 return ret;
68 static void smbcontrol_timeout(struct tevent_context *event_ctx,
69 struct tevent_timer *te,
70 struct timeval now,
71 void *private_data)
73 bool *timed_out = (bool *)private_data;
74 TALLOC_FREE(te);
75 *timed_out = True;
78 /* Wait for one or more reply messages */
80 static void wait_replies(struct messaging_context *msg_ctx,
81 bool multiple_replies)
83 struct tevent_timer *te;
84 bool timed_out = False;
86 if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
87 timeval_current_ofs(timeout, 0),
88 smbcontrol_timeout, (void *)&timed_out))) {
89 DEBUG(0, ("tevent_add_timer failed\n"));
90 return;
93 while (!timed_out) {
94 int ret;
95 if (num_replies > 0 && !multiple_replies)
96 break;
97 ret = tevent_loop_once(messaging_event_context(msg_ctx));
98 if (ret != 0) {
99 break;
104 /* Message handler callback that displays the PID and a string on stdout */
106 static void print_pid_string_cb(struct messaging_context *msg,
107 void *private_data,
108 uint32_t msg_type,
109 struct server_id pid,
110 DATA_BLOB *data)
112 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
113 (int)data->length, (const char *)data->data);
114 num_replies++;
117 /* Message handler callback that displays a string on stdout */
119 static void print_string_cb(struct messaging_context *msg,
120 void *private_data,
121 uint32_t msg_type,
122 struct server_id pid,
123 DATA_BLOB *data)
125 printf("%.*s", (int)data->length, (const char *)data->data);
126 num_replies++;
129 /* Send no message. Useful for testing. */
131 static bool do_noop(struct messaging_context *msg_ctx,
132 const struct server_id pid,
133 const int argc, const char **argv)
135 if (argc != 1) {
136 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
137 return False;
140 /* Move along, nothing to see here */
142 return True;
145 /* Send a debug string */
147 static bool do_debug(struct messaging_context *msg_ctx,
148 const struct server_id pid,
149 const int argc, const char **argv)
151 if (argc != 2) {
152 fprintf(stderr, "Usage: smbcontrol <dest> debug "
153 "<debug-string>\n");
154 return False;
157 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
158 strlen(argv[1]) + 1);
161 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
163 /* Return the name of a process given it's PID. This will only work on Linux,
164 * but that's probably moot since this whole stack tracing implementatino is
165 * Linux-specific anyway.
167 static const char * procname(pid_t pid, char * buf, size_t bufsz)
169 char path[64];
170 FILE * fp;
172 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
173 (unsigned long long)pid);
174 if ((fp = fopen(path, "r")) == NULL) {
175 return NULL;
178 fgets(buf, bufsz, fp);
180 fclose(fp);
181 return buf;
184 static void print_stack_trace(pid_t pid, int * count)
186 void * pinfo = NULL;
187 unw_addr_space_t aspace = NULL;
188 unw_cursor_t cursor;
189 unw_word_t ip, sp;
191 char nbuf[256];
192 unw_word_t off;
194 int ret;
196 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
197 fprintf(stderr,
198 "Failed to attach to process %llu: %s\n",
199 (unsigned long long)pid, strerror(errno));
200 return;
203 /* Wait until the attach is complete. */
204 waitpid(pid, NULL, 0);
206 if (((pinfo = _UPT_create(pid)) == NULL) ||
207 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
208 /* Probably out of memory. */
209 fprintf(stderr,
210 "Unable to initialize stack unwind for process %llu\n",
211 (unsigned long long)pid);
212 goto cleanup;
215 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
216 fprintf(stderr,
217 "Unable to unwind stack for process %llu: %s\n",
218 (unsigned long long)pid, unw_strerror(ret));
219 goto cleanup;
222 if (*count > 0) {
223 printf("\n");
226 if (procname(pid, nbuf, sizeof(nbuf))) {
227 printf("Stack trace for process %llu (%s):\n",
228 (unsigned long long)pid, nbuf);
229 } else {
230 printf("Stack trace for process %llu:\n",
231 (unsigned long long)pid);
234 while (unw_step(&cursor) > 0) {
235 ip = sp = off = 0;
236 unw_get_reg(&cursor, UNW_REG_IP, &ip);
237 unw_get_reg(&cursor, UNW_REG_SP, &sp);
239 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
240 if (ret != 0 && ret != -UNW_ENOMEM) {
241 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
243 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
244 nbuf, (long long)off, (long long)ip,
245 (long long)sp);
248 (*count)++;
250 cleanup:
251 if (aspace) {
252 unw_destroy_addr_space(aspace);
255 if (pinfo) {
256 _UPT_destroy(pinfo);
259 ptrace(PTRACE_DETACH, pid, NULL, NULL);
262 static int stack_trace_connection(struct db_record *rec,
263 const struct connections_key *key,
264 const struct connections_data *crec,
265 void *priv)
267 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
269 return 0;
272 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
273 const struct server_id pid,
274 const int argc, const char **argv)
276 pid_t dest;
277 int count = 0;
279 if (argc != 1) {
280 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
281 return False;
284 dest = procid_to_pid(&pid);
286 if (dest != 0) {
287 /* It would be nice to be able to make sure that this PID is
288 * the PID of a smbd/winbind/nmbd process, not some random PID
289 * the user liked the look of. It doesn't seem like it's worth
290 * the effort at the moment, however.
292 print_stack_trace(dest, &count);
293 } else {
294 connections_forall(stack_trace_connection, &count);
297 return True;
300 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
302 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
303 const struct server_id pid,
304 const int argc, const char **argv)
306 fprintf(stderr,
307 "Daemon stack tracing is not supported on this platform\n");
308 return False;
311 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
313 /* Inject a fault (fatal signal) into a running smbd */
315 static bool do_inject_fault(struct messaging_context *msg_ctx,
316 const struct server_id pid,
317 const int argc, const char **argv)
319 if (argc != 2) {
320 fprintf(stderr, "Usage: smbcontrol <dest> inject "
321 "<bus|hup|term|internal|segv>\n");
322 return False;
325 #ifndef DEVELOPER
326 fprintf(stderr, "Fault injection is only available in "
327 "developer builds\n");
328 return False;
329 #else /* DEVELOPER */
331 int sig = 0;
333 if (strcmp(argv[1], "bus") == 0) {
334 sig = SIGBUS;
335 } else if (strcmp(argv[1], "hup") == 0) {
336 sig = SIGHUP;
337 } else if (strcmp(argv[1], "term") == 0) {
338 sig = SIGTERM;
339 } else if (strcmp(argv[1], "segv") == 0) {
340 sig = SIGSEGV;
341 } else if (strcmp(argv[1], "internal") == 0) {
342 /* Force an internal error, ie. an unclean exit. */
343 sig = -1;
344 } else {
345 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
346 return False;
349 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
350 &sig, sizeof(int));
352 #endif /* DEVELOPER */
355 /* Force a browser election */
357 static bool do_election(struct messaging_context *msg_ctx,
358 const struct server_id pid,
359 const int argc, const char **argv)
361 if (argc != 1) {
362 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
363 return False;
366 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
369 /* Ping a samba daemon process */
371 static void pong_cb(struct messaging_context *msg,
372 void *private_data,
373 uint32_t msg_type,
374 struct server_id pid,
375 DATA_BLOB *data)
377 char *src_string = procid_str(NULL, &pid);
378 printf("PONG from pid %s\n", src_string);
379 TALLOC_FREE(src_string);
380 num_replies++;
383 static bool do_ping(struct messaging_context *msg_ctx,
384 const struct server_id pid,
385 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(msg_ctx, pid, MSG_PING, NULL, 0))
395 return False;
397 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
399 wait_replies(msg_ctx, 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 messaging_deregister(msg_ctx, MSG_PONG, NULL);
408 return num_replies;
411 /* Set profiling options */
413 static bool do_profile(struct messaging_context *msg_ctx,
414 const struct server_id pid,
415 const int argc, const char **argv)
417 int v;
419 if (argc != 2) {
420 fprintf(stderr, "Usage: smbcontrol <dest> profile "
421 "<off|count|on|flush>\n");
422 return False;
425 if (strcmp(argv[1], "off") == 0) {
426 v = 0;
427 } else if (strcmp(argv[1], "count") == 0) {
428 v = 1;
429 } else if (strcmp(argv[1], "on") == 0) {
430 v = 2;
431 } else if (strcmp(argv[1], "flush") == 0) {
432 v = 3;
433 } else {
434 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
435 return False;
438 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
441 /* Return the profiling level */
443 static void profilelevel_cb(struct messaging_context *msg_ctx,
444 void *private_data,
445 uint32_t msg_type,
446 struct server_id pid,
447 DATA_BLOB *data)
449 int level;
450 const char *s;
452 num_replies++;
454 if (data->length != sizeof(int)) {
455 fprintf(stderr, "invalid message length %ld returned\n",
456 (unsigned long)data->length);
457 return;
460 memcpy(&level, data->data, sizeof(int));
462 switch (level) {
463 case 0:
464 s = "not enabled";
465 break;
466 case 1:
467 s = "off";
468 break;
469 case 3:
470 s = "count only";
471 break;
472 case 7:
473 s = "count and time";
474 break;
475 default:
476 s = "BOGUS";
477 break;
480 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
483 static void profilelevel_rqst(struct messaging_context *msg_ctx,
484 void *private_data,
485 uint32_t msg_type,
486 struct server_id pid,
487 DATA_BLOB *data)
489 int v = 0;
491 /* Send back a dummy reply */
493 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
496 static bool do_profilelevel(struct messaging_context *msg_ctx,
497 const struct server_id pid,
498 const int argc, const char **argv)
500 if (argc != 1) {
501 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
502 return False;
505 /* Send a message and register our interest in a reply */
507 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
508 return False;
510 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
511 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
512 profilelevel_rqst);
514 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
516 /* No replies were received within the timeout period */
518 if (num_replies == 0)
519 printf("No replies received\n");
521 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
523 return num_replies;
526 /* Display debug level settings */
528 static bool do_debuglevel(struct messaging_context *msg_ctx,
529 const struct server_id pid,
530 const int argc, const char **argv)
532 if (argc != 1) {
533 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
534 return False;
537 /* Send a message and register our interest in a reply */
539 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
540 return False;
542 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
544 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
546 /* No replies were received within the timeout period */
548 if (num_replies == 0)
549 printf("No replies received\n");
551 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
553 return num_replies;
556 /* Send a print notify message */
558 static bool do_printnotify(struct messaging_context *msg_ctx,
559 const struct server_id pid,
560 const int argc, const char **argv)
562 const char *cmd;
564 /* Check for subcommand */
566 if (argc == 1) {
567 fprintf(stderr, "Must specify subcommand:\n");
568 fprintf(stderr, "\tqueuepause <printername>\n");
569 fprintf(stderr, "\tqueueresume <printername>\n");
570 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
571 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
572 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
573 fprintf(stderr, "\tprinter <printername> <comment|port|"
574 "driver> <value>\n");
576 return False;
579 cmd = argv[1];
581 if (strcmp(cmd, "queuepause") == 0) {
583 if (argc != 3) {
584 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
585 " queuepause <printername>\n");
586 return False;
589 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
591 goto send;
593 } else if (strcmp(cmd, "queueresume") == 0) {
595 if (argc != 3) {
596 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
597 " queuereume <printername>\n");
598 return False;
601 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
603 goto send;
605 } else if (strcmp(cmd, "jobpause") == 0) {
606 int jobid;
608 if (argc != 4) {
609 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
610 " jobpause <printername> <unix-jobid>\n");
611 return False;
614 jobid = atoi(argv[3]);
616 notify_job_status_byname(
617 argv[2], jobid, JOB_STATUS_PAUSED,
618 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
620 goto send;
622 } else if (strcmp(cmd, "jobresume") == 0) {
623 int jobid;
625 if (argc != 4) {
626 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
627 " jobpause <printername> <unix-jobid>\n");
628 return False;
631 jobid = atoi(argv[3]);
633 notify_job_status_byname(
634 argv[2], jobid, JOB_STATUS_QUEUED,
635 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
637 goto send;
639 } else if (strcmp(cmd, "jobdelete") == 0) {
640 int jobid;
642 if (argc != 4) {
643 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
644 " jobpause <printername> <unix-jobid>\n");
645 return False;
648 jobid = atoi(argv[3]);
650 notify_job_status_byname(
651 argv[2], jobid, JOB_STATUS_DELETING,
652 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
654 notify_job_status_byname(
655 argv[2], jobid, JOB_STATUS_DELETING|
656 JOB_STATUS_DELETED,
657 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
659 goto send;
661 } else if (strcmp(cmd, "printer") == 0) {
662 uint32 attribute;
664 if (argc != 5) {
665 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
666 "printer <printername> <comment|port|driver> "
667 "<value>\n");
668 return False;
671 if (strcmp(argv[3], "comment") == 0) {
672 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
673 } else if (strcmp(argv[3], "port") == 0) {
674 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
675 } else if (strcmp(argv[3], "driver") == 0) {
676 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
677 } else {
678 fprintf(stderr, "Invalid printer command '%s'\n",
679 argv[3]);
680 return False;
683 notify_printer_byname(argv[2], attribute,
684 CONST_DISCARD(char *, argv[4]));
686 goto send;
689 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
690 return False;
692 send:
693 print_notify_send_messages(msg_ctx, 0);
694 return True;
697 /* Close a share */
699 static bool do_closeshare(struct messaging_context *msg_ctx,
700 const struct server_id pid,
701 const int argc, const char **argv)
703 if (argc != 2) {
704 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
705 "<sharename>\n");
706 return False;
709 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
710 strlen(argv[1]) + 1);
713 /* force a blocking lock retry */
715 static bool do_lockretry(struct messaging_context *msg_ctx,
716 const struct server_id pid,
717 const int argc, const char **argv)
719 if (argc != 1) {
720 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
721 return False;
724 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
727 /* force a validation of all brl entries, including re-sends. */
729 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
730 const struct server_id pid,
731 const int argc, const char **argv)
733 if (argc != 1) {
734 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
735 return False;
738 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
741 /* Force a SAM synchronisation */
743 static bool do_samsync(struct messaging_context *msg_ctx,
744 const struct server_id pid,
745 const int argc, const char **argv)
747 if (argc != 1) {
748 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
749 return False;
752 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
755 /* Force a SAM replication */
757 static bool do_samrepl(struct messaging_context *msg_ctx,
758 const struct server_id pid,
759 const int argc, const char **argv)
761 if (argc != 1) {
762 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
763 return False;
766 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
769 /* Display talloc pool usage */
771 static bool do_poolusage(struct messaging_context *msg_ctx,
772 const struct server_id pid,
773 const int argc, const char **argv)
775 if (argc != 1) {
776 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
777 return False;
780 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
782 /* Send a message and register our interest in a reply */
784 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
785 return False;
787 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
789 /* No replies were received within the timeout period */
791 if (num_replies == 0)
792 printf("No replies received\n");
794 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
796 return num_replies;
799 /* Perform a dmalloc mark */
801 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
802 const struct server_id pid,
803 const int argc, const char **argv)
805 if (argc != 1) {
806 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
807 return False;
810 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
813 /* Perform a dmalloc changed */
815 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
816 const struct server_id pid,
817 const int argc, const char **argv)
819 if (argc != 1) {
820 fprintf(stderr, "Usage: smbcontrol <dest> "
821 "dmalloc-log-changed\n");
822 return False;
825 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
826 NULL, 0);
829 /* Shutdown a server process */
831 static bool do_shutdown(struct messaging_context *msg_ctx,
832 const struct server_id pid,
833 const int argc, const char **argv)
835 if (argc != 1) {
836 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
837 return False;
840 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
843 /* Notify a driver upgrade */
845 static bool do_drvupgrade(struct messaging_context *msg_ctx,
846 const struct server_id pid,
847 const int argc, const char **argv)
849 if (argc != 2) {
850 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
851 "<driver-name>\n");
852 return False;
855 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
856 strlen(argv[1]) + 1);
859 static bool do_winbind_online(struct messaging_context *msg_ctx,
860 const struct server_id pid,
861 const int argc, const char **argv)
863 TDB_CONTEXT *tdb;
865 if (argc != 1) {
866 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
867 return False;
870 /* Remove the entry in the winbindd_cache tdb to tell a later
871 starting winbindd that we're online. */
873 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
874 if (!tdb) {
875 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
876 cache_path("winbindd_cache.tdb"));
877 return False;
880 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
881 tdb_close(tdb);
883 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
886 static bool do_winbind_offline(struct messaging_context *msg_ctx,
887 const struct server_id pid,
888 const int argc, const char **argv)
890 TDB_CONTEXT *tdb;
891 bool ret = False;
892 int retry = 0;
894 if (argc != 1) {
895 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
896 return False;
899 /* Create an entry in the winbindd_cache tdb to tell a later
900 starting winbindd that we're offline. We may actually create
901 it here... */
903 tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
904 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
905 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
907 if (!tdb) {
908 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
909 cache_path("winbindd_cache.tdb"));
910 return False;
913 /* There's a potential race condition that if a child
914 winbindd detects a domain is online at the same time
915 we're trying to tell it to go offline that it might
916 delete the record we add between us adding it and
917 sending the message. Minimize this by retrying up to
918 5 times. */
920 for (retry = 0; retry < 5; retry++) {
921 TDB_DATA d;
922 uint8 buf[4];
924 ZERO_STRUCT(d);
926 SIVAL(buf, 0, time(NULL));
927 d.dptr = buf;
928 d.dsize = 4;
930 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
932 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
933 NULL, 0);
935 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
936 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
938 if (!d.dptr || d.dsize != 4) {
939 SAFE_FREE(d.dptr);
940 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
941 } else {
942 SAFE_FREE(d.dptr);
943 break;
947 tdb_close(tdb);
948 return ret;
951 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
952 const struct server_id pid,
953 const int argc, const char **argv)
955 struct server_id myid;
957 myid = pid_to_procid(sys_getpid());
959 if (argc != 1) {
960 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
961 return False;
964 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
965 print_pid_string_cb);
967 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
968 sizeof(myid)))
969 return False;
971 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
973 /* No replies were received within the timeout period */
975 if (num_replies == 0)
976 printf("No replies received\n");
978 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
980 return num_replies;
983 static bool do_dump_event_list(struct messaging_context *msg_ctx,
984 const struct server_id pid,
985 const int argc, const char **argv)
987 struct server_id myid;
989 myid = pid_to_procid(sys_getpid());
991 if (argc != 1) {
992 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
993 return False;
996 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
999 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1000 const struct server_id pid,
1001 const int argc, const char **argv)
1003 const char *domain = NULL;
1004 int domain_len = 0;
1005 struct server_id myid;
1006 uint8_t *buf = NULL;
1007 int buf_len = 0;
1009 myid = pid_to_procid(sys_getpid());
1011 if (argc < 1 || argc > 2) {
1012 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1013 "<domain>\n");
1014 return false;
1017 if (argc == 2) {
1018 domain = argv[1];
1019 domain_len = strlen(argv[1]) + 1;
1022 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1023 print_pid_string_cb);
1025 buf_len = sizeof(myid)+domain_len;
1026 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1027 if (!buf) {
1028 return false;
1031 memcpy(buf, &myid, sizeof(myid));
1032 memcpy(&buf[sizeof(myid)], domain, domain_len);
1034 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1035 buf, buf_len))
1037 SAFE_FREE(buf);
1038 return false;
1041 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1043 /* No replies were received within the timeout period */
1045 SAFE_FREE(buf);
1046 if (num_replies == 0) {
1047 printf("No replies received\n");
1050 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1052 return num_replies;
1055 static void winbind_validate_cache_cb(struct messaging_context *msg,
1056 void *private_data,
1057 uint32_t msg_type,
1058 struct server_id pid,
1059 DATA_BLOB *data)
1061 char *src_string = procid_str(NULL, &pid);
1062 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1063 (*(data->data) == 0 ? "" : "NOT "), src_string);
1064 TALLOC_FREE(src_string);
1065 num_replies++;
1068 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1069 const struct server_id pid,
1070 const int argc, const char **argv)
1072 struct server_id myid = pid_to_procid(sys_getpid());
1074 if (argc != 1) {
1075 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1076 return False;
1079 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1080 winbind_validate_cache_cb);
1082 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1083 sizeof(myid))) {
1084 return False;
1087 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1089 if (num_replies == 0) {
1090 printf("No replies received\n");
1093 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1095 return num_replies;
1098 static bool do_reload_config(struct messaging_context *msg_ctx,
1099 const struct server_id pid,
1100 const int argc, const char **argv)
1102 if (argc != 1) {
1103 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1104 return False;
1107 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1110 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1112 fstring unix_name;
1113 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1114 fstrcpy(unix_name, name);
1115 strupper_m(unix_name);
1116 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1117 n->name_type = (unsigned int)type & 0xFF;
1118 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1121 static bool do_nodestatus(struct messaging_context *msg_ctx,
1122 const struct server_id pid,
1123 const int argc, const char **argv)
1125 struct packet_struct p;
1127 if (argc != 2) {
1128 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1129 return False;
1132 ZERO_STRUCT(p);
1134 p.ip = interpret_addr2(argv[1]);
1135 p.port = 137;
1136 p.packet_type = NMB_PACKET;
1138 p.packet.nmb.header.name_trn_id = 10;
1139 p.packet.nmb.header.opcode = 0;
1140 p.packet.nmb.header.response = False;
1141 p.packet.nmb.header.nm_flags.bcast = False;
1142 p.packet.nmb.header.nm_flags.recursion_available = False;
1143 p.packet.nmb.header.nm_flags.recursion_desired = False;
1144 p.packet.nmb.header.nm_flags.trunc = False;
1145 p.packet.nmb.header.nm_flags.authoritative = False;
1146 p.packet.nmb.header.rcode = 0;
1147 p.packet.nmb.header.qdcount = 1;
1148 p.packet.nmb.header.ancount = 0;
1149 p.packet.nmb.header.nscount = 0;
1150 p.packet.nmb.header.arcount = 0;
1151 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1152 p.packet.nmb.question.question_type = 0x21;
1153 p.packet.nmb.question.question_class = 0x1;
1155 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1158 /* A list of message type supported */
1160 static const struct {
1161 const char *name; /* Option name */
1162 bool (*fn)(struct messaging_context *msg_ctx,
1163 const struct server_id pid,
1164 const int argc, const char **argv);
1165 const char *help; /* Short help text */
1166 } msg_types[] = {
1167 { "debug", do_debug, "Set debuglevel" },
1168 { "force-election", do_election,
1169 "Force a browse election" },
1170 { "ping", do_ping, "Elicit a response" },
1171 { "profile", do_profile, "" },
1172 { "inject", do_inject_fault,
1173 "Inject a fatal signal into a running smbd"},
1174 { "stacktrace", do_daemon_stack_trace,
1175 "Display a stack trace of a daemon" },
1176 { "profilelevel", do_profilelevel, "" },
1177 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1178 { "printnotify", do_printnotify, "Send a print notify message" },
1179 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1180 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1181 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1182 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1183 { "samrepl", do_samrepl, "Initiate SAM replication" },
1184 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1185 { "dmalloc-mark", do_dmalloc_mark, "" },
1186 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1187 { "shutdown", do_shutdown, "Shut down daemon" },
1188 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1189 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1190 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1191 { "online", do_winbind_online, "Ask winbind to go into online state"},
1192 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1193 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1194 { "dump-event-list", do_dump_event_list, "Dump event list"},
1195 { "validate-cache" , do_winbind_validate_cache,
1196 "Validate winbind's credential cache" },
1197 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1198 { "noop", do_noop, "Do nothing" },
1199 { NULL }
1202 /* Display usage information */
1204 static void usage(poptContext pc)
1206 int i;
1208 poptPrintHelp(pc, stderr, 0);
1210 fprintf(stderr, "\n");
1211 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1212 "process ID\n");
1214 fprintf(stderr, "\n");
1215 fprintf(stderr, "<message-type> is one of:\n");
1217 for (i = 0; msg_types[i].name; i++)
1218 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1219 msg_types[i].help);
1221 fprintf(stderr, "\n");
1223 exit(1);
1226 /* Return the pid number for a string destination */
1228 static struct server_id parse_dest(const char *dest)
1230 struct server_id result = {-1};
1231 pid_t pid;
1233 /* Zero is a special return value for broadcast to all processes */
1235 if (strequal(dest, "all")) {
1236 return interpret_pid(MSG_BROADCAST_PID_STR);
1239 /* Try self - useful for testing */
1241 if (strequal(dest, "self")) {
1242 return pid_to_procid(sys_getpid());
1245 /* Fix winbind typo. */
1246 if (strequal(dest, "winbind")) {
1247 dest = "winbindd";
1250 /* Check for numeric pid number */
1251 result = interpret_pid(dest);
1253 /* Zero isn't valid if not "all". */
1254 if (result.pid && procid_valid(&result)) {
1255 return result;
1258 /* Look up other destinations in pidfile directory */
1260 if ((pid = pidfile_pid(dest)) != 0) {
1261 return pid_to_procid(pid);
1264 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1266 return result;
1269 /* Execute smbcontrol command */
1271 static bool do_command(struct messaging_context *msg_ctx,
1272 int argc, const char **argv)
1274 const char *dest = argv[0], *command = argv[1];
1275 struct server_id pid;
1276 int i;
1278 /* Check destination */
1280 pid = parse_dest(dest);
1281 if (!procid_valid(&pid)) {
1282 return False;
1285 /* Check command */
1287 for (i = 0; msg_types[i].name; i++) {
1288 if (strequal(command, msg_types[i].name))
1289 return msg_types[i].fn(msg_ctx, pid,
1290 argc - 1, argv + 1);
1293 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1295 return False;
1298 static void smbcontrol_help(poptContext pc,
1299 enum poptCallbackReason preason,
1300 struct poptOption * poption,
1301 const char * parg,
1302 void * pdata)
1304 if (poption->shortName != '?') {
1305 poptPrintUsage(pc, stdout, 0);
1306 } else {
1307 usage(pc);
1310 exit(0);
1313 struct poptOption help_options[] = {
1314 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1315 NULL, NULL },
1316 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1317 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1318 { NULL }
1321 /* Main program */
1323 int main(int argc, const char **argv)
1325 poptContext pc;
1326 int opt;
1327 struct tevent_context *evt_ctx;
1328 struct messaging_context *msg_ctx;
1330 static struct poptOption long_options[] = {
1331 /* POPT_AUTOHELP */
1332 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1333 0, "Help options:", NULL },
1334 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1335 "Set timeout value in seconds", "TIMEOUT" },
1337 POPT_COMMON_SAMBA
1338 POPT_TABLEEND
1340 TALLOC_CTX *frame = talloc_stackframe();
1341 int ret = 0;
1343 load_case_tables();
1345 setup_logging(argv[0],True);
1347 /* Parse command line arguments using popt */
1349 pc = poptGetContext(
1350 "smbcontrol", argc, (const char **)argv, long_options, 0);
1352 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1353 "<parameters>");
1355 if (argc == 1)
1356 usage(pc);
1358 while ((opt = poptGetNextOpt(pc)) != -1) {
1359 switch(opt) {
1360 case 't': /* --timeout */
1361 break;
1362 default:
1363 fprintf(stderr, "Invalid option\n");
1364 poptPrintHelp(pc, stderr, 0);
1365 break;
1369 /* We should now have the remaining command line arguments in
1370 argv. The argc parameter should have been decremented to the
1371 correct value in the above switch statement. */
1373 argv = (const char **)poptGetArgs(pc);
1374 argc = 0;
1375 if (argv != NULL) {
1376 while (argv[argc] != NULL) {
1377 argc++;
1381 if (argc <= 1)
1382 usage(pc);
1384 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1386 /* Need to invert sense of return code -- samba
1387 * routines mostly return True==1 for success, but
1388 * shell needs 0. */
1390 if (!(evt_ctx = tevent_context_init(NULL)) ||
1391 !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1392 fprintf(stderr, "could not init messaging context\n");
1393 TALLOC_FREE(frame);
1394 exit(1);
1397 ret = !do_command(msg_ctx, argc, argv);
1398 TALLOC_FREE(frame);
1399 return ret;