tevent: expose tevent_context_init_ops
[Samba/gebeck_regimport.git] / source3 / utils / smbcontrol.c
blob54e10d8b42fa76c6719955576feea9626dba7243
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"
27 #include "system/filesys.h"
28 #include "popt_common.h"
29 #include "librpc/gen_ndr/spoolss.h"
30 #include "nt_printing.h"
31 #include "printing/notify.h"
32 #include "libsmb/nmblib.h"
33 #include "messages.h"
34 #include "util_tdb.h"
36 #if HAVE_LIBUNWIND_H
37 #include <libunwind.h>
38 #endif
40 #if HAVE_LIBUNWIND_PTRACE_H
41 #include <libunwind-ptrace.h>
42 #endif
44 #if HAVE_SYS_PTRACE_H
45 #include <sys/ptrace.h>
46 #endif
48 /* Default timeout value when waiting for replies (in seconds) */
50 #define DEFAULT_TIMEOUT 10
52 static int timeout = DEFAULT_TIMEOUT;
53 static int num_replies; /* Used by message callback fns */
55 /* Send a message to a destination pid. Zero means broadcast smbd. */
57 static bool send_message(struct messaging_context *msg_ctx,
58 struct server_id pid, int msg_type,
59 const void *buf, int len)
61 bool ret;
62 int n_sent = 0;
64 if (procid_to_pid(&pid) != 0)
65 return NT_STATUS_IS_OK(
66 messaging_send_buf(msg_ctx, pid, msg_type,
67 (const uint8 *)buf, len));
69 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
70 DEBUG(10,("smbcontrol/send_message: broadcast message to "
71 "%d processes\n", n_sent));
73 return ret;
76 static void smbcontrol_timeout(struct tevent_context *event_ctx,
77 struct tevent_timer *te,
78 struct timeval now,
79 void *private_data)
81 bool *timed_out = (bool *)private_data;
82 TALLOC_FREE(te);
83 *timed_out = True;
86 /* Wait for one or more reply messages */
88 static void wait_replies(struct tevent_context *ev_ctx,
89 struct messaging_context *msg_ctx,
90 bool multiple_replies)
92 struct tevent_timer *te;
93 bool timed_out = False;
95 if (!(te = tevent_add_timer(ev_ctx, NULL,
96 timeval_current_ofs(timeout, 0),
97 smbcontrol_timeout, (void *)&timed_out))) {
98 DEBUG(0, ("tevent_add_timer failed\n"));
99 return;
102 while (!timed_out) {
103 int ret;
104 if (num_replies > 0 && !multiple_replies)
105 break;
106 ret = tevent_loop_once(ev_ctx);
107 if (ret != 0) {
108 break;
113 /* Message handler callback that displays the PID and a string on stdout */
115 static void print_pid_string_cb(struct messaging_context *msg,
116 void *private_data,
117 uint32_t msg_type,
118 struct server_id pid,
119 DATA_BLOB *data)
121 char *pidstr;
123 pidstr = server_id_str(talloc_tos(), &pid);
124 printf("PID %s: %.*s", pidstr, (int)data->length,
125 (const char *)data->data);
126 TALLOC_FREE(pidstr);
127 num_replies++;
130 /* Message handler callback that displays a string on stdout */
132 static void print_string_cb(struct messaging_context *msg,
133 void *private_data,
134 uint32_t msg_type,
135 struct server_id pid,
136 DATA_BLOB *data)
138 printf("%*s", (int)data->length, (const char *)data->data);
139 num_replies++;
142 /* Send no message. Useful for testing. */
144 static bool do_noop(struct tevent_context *ev_ctx,
145 struct messaging_context *msg_ctx,
146 const struct server_id pid,
147 const int argc, const char **argv)
149 if (argc != 1) {
150 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
151 return False;
154 /* Move along, nothing to see here */
156 return True;
159 /* Send a debug string */
161 static bool do_debug(struct tevent_context *ev_ctx,
162 struct messaging_context *msg_ctx,
163 const struct server_id pid,
164 const int argc, const char **argv)
166 if (argc != 2) {
167 fprintf(stderr, "Usage: smbcontrol <dest> debug "
168 "<debug-string>\n");
169 return False;
172 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
173 strlen(argv[1]) + 1);
177 static bool do_idmap(struct tevent_context *ev,
178 struct messaging_context *msg_ctx,
179 const struct server_id pid,
180 const int argc, const char **argv)
182 static const char* usage = "Usage: "
183 "smbcontrol <dest> idmap <cmd> [arg]\n"
184 "\tcmd:"
185 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
186 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
187 const char* arg = NULL;
188 int arglen = 0;
189 int msg_type;
191 switch (argc) {
192 case 2:
193 break;
194 case 3:
195 arg = argv[2];
196 arglen = strlen(arg) + 1;
197 break;
198 default:
199 fprintf(stderr, "%s", usage);
200 return false;
203 if (strcmp(argv[1], "delete") == 0) {
204 msg_type = ID_CACHE_DELETE;
206 else if (strcmp(argv[1], "kill") == 0) {
207 msg_type = ID_CACHE_KILL;
209 else if (strcmp(argv[1], "help") == 0) {
210 fprintf(stdout, "%s", usage);
211 return true;
213 else {
214 fprintf(stderr, "%s", usage);
215 return false;
218 return send_message(msg_ctx, pid, msg_type, arg, arglen);
222 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
224 /* Return the name of a process given it's PID. This will only work on Linux,
225 * but that's probably moot since this whole stack tracing implementatino is
226 * Linux-specific anyway.
228 static const char * procname(pid_t pid, char * buf, size_t bufsz)
230 char path[64];
231 FILE * fp;
233 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
234 (unsigned long long)pid);
235 if ((fp = fopen(path, "r")) == NULL) {
236 return NULL;
239 fgets(buf, bufsz, fp);
241 fclose(fp);
242 return buf;
245 static void print_stack_trace(pid_t pid, int * count)
247 void * pinfo = NULL;
248 unw_addr_space_t aspace = NULL;
249 unw_cursor_t cursor;
250 unw_word_t ip, sp;
252 char nbuf[256];
253 unw_word_t off;
255 int ret;
257 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
258 fprintf(stderr,
259 "Failed to attach to process %llu: %s\n",
260 (unsigned long long)pid, strerror(errno));
261 return;
264 /* Wait until the attach is complete. */
265 waitpid(pid, NULL, 0);
267 if (((pinfo = _UPT_create(pid)) == NULL) ||
268 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
269 /* Probably out of memory. */
270 fprintf(stderr,
271 "Unable to initialize stack unwind for process %llu\n",
272 (unsigned long long)pid);
273 goto cleanup;
276 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
277 fprintf(stderr,
278 "Unable to unwind stack for process %llu: %s\n",
279 (unsigned long long)pid, unw_strerror(ret));
280 goto cleanup;
283 if (*count > 0) {
284 printf("\n");
287 if (procname(pid, nbuf, sizeof(nbuf))) {
288 printf("Stack trace for process %llu (%s):\n",
289 (unsigned long long)pid, nbuf);
290 } else {
291 printf("Stack trace for process %llu:\n",
292 (unsigned long long)pid);
295 while (unw_step(&cursor) > 0) {
296 ip = sp = off = 0;
297 unw_get_reg(&cursor, UNW_REG_IP, &ip);
298 unw_get_reg(&cursor, UNW_REG_SP, &sp);
300 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
301 if (ret != 0 && ret != -UNW_ENOMEM) {
302 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
304 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
305 nbuf, (long long)off, (long long)ip,
306 (long long)sp);
309 (*count)++;
311 cleanup:
312 if (aspace) {
313 unw_destroy_addr_space(aspace);
316 if (pinfo) {
317 _UPT_destroy(pinfo);
320 ptrace(PTRACE_DETACH, pid, NULL, NULL);
323 static int stack_trace_connection(const struct connections_key *key,
324 const struct connections_data *crec,
325 void *priv)
327 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
329 return 0;
332 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
333 struct messaging_context *msg_ctx,
334 const struct server_id pid,
335 const int argc, const char **argv)
337 pid_t dest;
338 int count = 0;
340 if (argc != 1) {
341 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
342 return False;
345 dest = procid_to_pid(&pid);
347 if (dest != 0) {
348 /* It would be nice to be able to make sure that this PID is
349 * the PID of a smbd/winbind/nmbd process, not some random PID
350 * the user liked the look of. It doesn't seem like it's worth
351 * the effort at the moment, however.
353 print_stack_trace(dest, &count);
354 } else {
355 connections_forall_read(stack_trace_connection, &count);
358 return True;
361 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
363 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
364 struct messaging_context *msg_ctx,
365 const struct server_id pid,
366 const int argc, const char **argv)
368 fprintf(stderr,
369 "Daemon stack tracing is not supported on this platform\n");
370 return False;
373 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
375 /* Inject a fault (fatal signal) into a running smbd */
377 static bool do_inject_fault(struct tevent_context *ev_ctx,
378 struct messaging_context *msg_ctx,
379 const struct server_id pid,
380 const int argc, const char **argv)
382 if (argc != 2) {
383 fprintf(stderr, "Usage: smbcontrol <dest> inject "
384 "<bus|hup|term|internal|segv>\n");
385 return False;
388 #ifndef DEVELOPER
389 fprintf(stderr, "Fault injection is only available in "
390 "developer builds\n");
391 return False;
392 #else /* DEVELOPER */
394 int sig = 0;
396 if (strcmp(argv[1], "bus") == 0) {
397 sig = SIGBUS;
398 } else if (strcmp(argv[1], "hup") == 0) {
399 sig = SIGHUP;
400 } else if (strcmp(argv[1], "term") == 0) {
401 sig = SIGTERM;
402 } else if (strcmp(argv[1], "segv") == 0) {
403 sig = SIGSEGV;
404 } else if (strcmp(argv[1], "internal") == 0) {
405 /* Force an internal error, ie. an unclean exit. */
406 sig = -1;
407 } else {
408 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
409 return False;
412 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
413 &sig, sizeof(int));
415 #endif /* DEVELOPER */
418 /* Force a browser election */
420 static bool do_election(struct tevent_context *ev_ctx,
421 struct messaging_context *msg_ctx,
422 const struct server_id pid,
423 const int argc, const char **argv)
425 if (argc != 1) {
426 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
427 return False;
430 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
433 /* Ping a samba daemon process */
435 static void pong_cb(struct messaging_context *msg,
436 void *private_data,
437 uint32_t msg_type,
438 struct server_id pid,
439 DATA_BLOB *data)
441 char *src_string = server_id_str(NULL, &pid);
442 printf("PONG from pid %s\n", src_string);
443 TALLOC_FREE(src_string);
444 num_replies++;
447 static bool do_ping(struct tevent_context *ev_ctx,
448 struct messaging_context *msg_ctx,
449 const struct server_id pid,
450 const int argc, const char **argv)
452 if (argc != 1) {
453 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
454 return False;
457 /* Send a message and register our interest in a reply */
459 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
460 return False;
462 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
464 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
466 /* No replies were received within the timeout period */
468 if (num_replies == 0)
469 printf("No replies received\n");
471 messaging_deregister(msg_ctx, MSG_PONG, NULL);
473 return num_replies;
476 /* Set profiling options */
478 static bool do_profile(struct tevent_context *ev_ctx,
479 struct messaging_context *msg_ctx,
480 const struct server_id pid,
481 const int argc, const char **argv)
483 int v;
485 if (argc != 2) {
486 fprintf(stderr, "Usage: smbcontrol <dest> profile "
487 "<off|count|on|flush>\n");
488 return False;
491 if (strcmp(argv[1], "off") == 0) {
492 v = 0;
493 } else if (strcmp(argv[1], "count") == 0) {
494 v = 1;
495 } else if (strcmp(argv[1], "on") == 0) {
496 v = 2;
497 } else if (strcmp(argv[1], "flush") == 0) {
498 v = 3;
499 } else {
500 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
501 return False;
504 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
507 /* Return the profiling level */
509 static void profilelevel_cb(struct messaging_context *msg_ctx,
510 void *private_data,
511 uint32_t msg_type,
512 struct server_id pid,
513 DATA_BLOB *data)
515 int level;
516 const char *s;
518 num_replies++;
520 if (data->length != sizeof(int)) {
521 fprintf(stderr, "invalid message length %ld returned\n",
522 (unsigned long)data->length);
523 return;
526 memcpy(&level, data->data, sizeof(int));
528 switch (level) {
529 case 0:
530 s = "not enabled";
531 break;
532 case 1:
533 s = "off";
534 break;
535 case 3:
536 s = "count only";
537 break;
538 case 7:
539 s = "count and time";
540 break;
541 default:
542 s = "BOGUS";
543 break;
546 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
549 static void profilelevel_rqst(struct messaging_context *msg_ctx,
550 void *private_data,
551 uint32_t msg_type,
552 struct server_id pid,
553 DATA_BLOB *data)
555 int v = 0;
557 /* Send back a dummy reply */
559 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
562 static bool do_profilelevel(struct tevent_context *ev_ctx,
563 struct messaging_context *msg_ctx,
564 const struct server_id pid,
565 const int argc, const char **argv)
567 if (argc != 1) {
568 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
569 return False;
572 /* Send a message and register our interest in a reply */
574 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
575 return False;
577 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
578 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
579 profilelevel_rqst);
581 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
583 /* No replies were received within the timeout period */
585 if (num_replies == 0)
586 printf("No replies received\n");
588 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
590 return num_replies;
593 /* Display debug level settings */
595 static bool do_debuglevel(struct tevent_context *ev_ctx,
596 struct messaging_context *msg_ctx,
597 const struct server_id pid,
598 const int argc, const char **argv)
600 if (argc != 1) {
601 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
602 return False;
605 /* Send a message and register our interest in a reply */
607 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
608 return False;
610 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
612 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
614 /* No replies were received within the timeout period */
616 if (num_replies == 0)
617 printf("No replies received\n");
619 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
621 return num_replies;
624 /* Send a print notify message */
626 static bool do_printnotify(struct tevent_context *ev_ctx,
627 struct messaging_context *msg_ctx,
628 const struct server_id pid,
629 const int argc, const char **argv)
631 const char *cmd;
633 /* Check for subcommand */
635 if (argc == 1) {
636 fprintf(stderr, "Must specify subcommand:\n");
637 fprintf(stderr, "\tqueuepause <printername>\n");
638 fprintf(stderr, "\tqueueresume <printername>\n");
639 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
640 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
641 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
642 fprintf(stderr, "\tprinter <printername> <comment|port|"
643 "driver> <value>\n");
645 return False;
648 cmd = argv[1];
650 if (strcmp(cmd, "queuepause") == 0) {
652 if (argc != 3) {
653 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
654 " queuepause <printername>\n");
655 return False;
658 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
659 PRINTER_STATUS_PAUSED);
661 goto send;
663 } else if (strcmp(cmd, "queueresume") == 0) {
665 if (argc != 3) {
666 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
667 " queuereume <printername>\n");
668 return False;
671 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
672 PRINTER_STATUS_OK);
674 goto send;
676 } else if (strcmp(cmd, "jobpause") == 0) {
677 int jobid;
679 if (argc != 4) {
680 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
681 " jobpause <printername> <unix-jobid>\n");
682 return False;
685 jobid = atoi(argv[3]);
687 notify_job_status_byname(
688 ev_ctx, msg_ctx,
689 argv[2], jobid, JOB_STATUS_PAUSED,
690 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
692 goto send;
694 } else if (strcmp(cmd, "jobresume") == 0) {
695 int jobid;
697 if (argc != 4) {
698 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
699 " jobpause <printername> <unix-jobid>\n");
700 return False;
703 jobid = atoi(argv[3]);
705 notify_job_status_byname(
706 ev_ctx, msg_ctx,
707 argv[2], jobid, JOB_STATUS_QUEUED,
708 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
710 goto send;
712 } else if (strcmp(cmd, "jobdelete") == 0) {
713 int jobid;
715 if (argc != 4) {
716 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
717 " jobpause <printername> <unix-jobid>\n");
718 return False;
721 jobid = atoi(argv[3]);
723 notify_job_status_byname(
724 ev_ctx, msg_ctx,
725 argv[2], jobid, JOB_STATUS_DELETING,
726 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
728 notify_job_status_byname(
729 ev_ctx, msg_ctx,
730 argv[2], jobid, JOB_STATUS_DELETING|
731 JOB_STATUS_DELETED,
732 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
734 goto send;
736 } else if (strcmp(cmd, "printer") == 0) {
737 uint32 attribute;
739 if (argc != 5) {
740 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
741 "printer <printername> <comment|port|driver> "
742 "<value>\n");
743 return False;
746 if (strcmp(argv[3], "comment") == 0) {
747 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
748 } else if (strcmp(argv[3], "port") == 0) {
749 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
750 } else if (strcmp(argv[3], "driver") == 0) {
751 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
752 } else {
753 fprintf(stderr, "Invalid printer command '%s'\n",
754 argv[3]);
755 return False;
758 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
759 discard_const_p(char, argv[4]));
761 goto send;
764 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
765 return False;
767 send:
768 print_notify_send_messages(msg_ctx, 0);
769 return True;
772 /* Close a share */
774 static bool do_closeshare(struct tevent_context *ev_ctx,
775 struct messaging_context *msg_ctx,
776 const struct server_id pid,
777 const int argc, const char **argv)
779 if (argc != 2) {
780 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
781 "<sharename>\n");
782 return False;
785 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
786 strlen(argv[1]) + 1);
789 /* Tell winbindd an IP got dropped */
791 static bool do_ip_dropped(struct tevent_context *ev_ctx,
792 struct messaging_context *msg_ctx,
793 const struct server_id pid,
794 const int argc, const char **argv)
796 if (argc != 2) {
797 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
798 "<ip-address>\n");
799 return False;
802 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
803 strlen(argv[1]) + 1);
806 /* force a blocking lock retry */
808 static bool do_lockretry(struct tevent_context *ev_ctx,
809 struct messaging_context *msg_ctx,
810 const struct server_id pid,
811 const int argc, const char **argv)
813 if (argc != 1) {
814 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
815 return False;
818 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
821 /* force a validation of all brl entries, including re-sends. */
823 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
824 struct messaging_context *msg_ctx,
825 const struct server_id pid,
826 const int argc, const char **argv)
828 if (argc != 1) {
829 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
830 return False;
833 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
836 /* Display talloc pool usage */
838 static bool do_poolusage(struct tevent_context *ev_ctx,
839 struct messaging_context *msg_ctx,
840 const struct server_id pid,
841 const int argc, const char **argv)
843 if (argc != 1) {
844 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
845 return False;
848 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
850 /* Send a message and register our interest in a reply */
852 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
853 return False;
855 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
857 /* No replies were received within the timeout period */
859 if (num_replies == 0)
860 printf("No replies received\n");
862 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
864 return num_replies;
867 /* Perform a dmalloc mark */
869 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
870 struct messaging_context *msg_ctx,
871 const struct server_id pid,
872 const int argc, const char **argv)
874 if (argc != 1) {
875 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
876 return False;
879 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
882 /* Perform a dmalloc changed */
884 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
885 struct messaging_context *msg_ctx,
886 const struct server_id pid,
887 const int argc, const char **argv)
889 if (argc != 1) {
890 fprintf(stderr, "Usage: smbcontrol <dest> "
891 "dmalloc-log-changed\n");
892 return False;
895 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
896 NULL, 0);
899 /* Shutdown a server process */
901 static bool do_shutdown(struct tevent_context *ev_ctx,
902 struct messaging_context *msg_ctx,
903 const struct server_id pid,
904 const int argc, const char **argv)
906 if (argc != 1) {
907 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
908 return False;
911 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
914 /* Notify a driver upgrade */
916 static bool do_drvupgrade(struct tevent_context *ev_ctx,
917 struct messaging_context *msg_ctx,
918 const struct server_id pid,
919 const int argc, const char **argv)
921 if (argc != 2) {
922 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
923 "<driver-name>\n");
924 return False;
927 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
928 strlen(argv[1]) + 1);
931 static bool do_winbind_online(struct tevent_context *ev_ctx,
932 struct messaging_context *msg_ctx,
933 const struct server_id pid,
934 const int argc, const char **argv)
936 TDB_CONTEXT *tdb;
938 if (argc != 1) {
939 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
940 return False;
943 /* Remove the entry in the winbindd_cache tdb to tell a later
944 starting winbindd that we're online. */
946 tdb = tdb_open_log(state_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
947 if (!tdb) {
948 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
949 state_path("winbindd_cache.tdb"));
950 return False;
953 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
954 tdb_close(tdb);
956 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
959 static bool do_winbind_offline(struct tevent_context *ev_ctx,
960 struct messaging_context *msg_ctx,
961 const struct server_id pid,
962 const int argc, const char **argv)
964 TDB_CONTEXT *tdb;
965 bool ret = False;
966 int retry = 0;
968 if (argc != 1) {
969 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
970 return False;
973 /* Create an entry in the winbindd_cache tdb to tell a later
974 starting winbindd that we're offline. We may actually create
975 it here... */
977 tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
978 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
979 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
980 O_RDWR|O_CREAT, 0600);
982 if (!tdb) {
983 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
984 state_path("winbindd_cache.tdb"));
985 return False;
988 /* There's a potential race condition that if a child
989 winbindd detects a domain is online at the same time
990 we're trying to tell it to go offline that it might
991 delete the record we add between us adding it and
992 sending the message. Minimize this by retrying up to
993 5 times. */
995 for (retry = 0; retry < 5; retry++) {
996 TDB_DATA d;
997 uint8 buf[4];
999 ZERO_STRUCT(d);
1001 SIVAL(buf, 0, time(NULL));
1002 d.dptr = buf;
1003 d.dsize = 4;
1005 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1007 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1008 NULL, 0);
1010 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1011 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1013 if (!d.dptr || d.dsize != 4) {
1014 SAFE_FREE(d.dptr);
1015 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1016 } else {
1017 SAFE_FREE(d.dptr);
1018 break;
1022 tdb_close(tdb);
1023 return ret;
1026 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1027 struct messaging_context *msg_ctx,
1028 const struct server_id pid,
1029 const int argc, const char **argv)
1031 struct server_id myid;
1033 myid = messaging_server_id(msg_ctx);
1035 if (argc != 1) {
1036 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1037 return False;
1040 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1041 print_pid_string_cb);
1043 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1044 sizeof(myid)))
1045 return False;
1047 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1049 /* No replies were received within the timeout period */
1051 if (num_replies == 0)
1052 printf("No replies received\n");
1054 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1056 return num_replies;
1059 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1060 struct messaging_context *msg_ctx,
1061 const struct server_id pid,
1062 const int argc, const char **argv)
1064 if (argc != 1) {
1065 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1066 return False;
1069 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1072 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1073 struct messaging_context *msg_ctx,
1074 const struct server_id pid,
1075 const int argc, const char **argv)
1077 const char *domain = NULL;
1078 int domain_len = 0;
1079 struct server_id myid;
1080 uint8_t *buf = NULL;
1081 int buf_len = 0;
1083 myid = messaging_server_id(msg_ctx);
1085 if (argc < 1 || argc > 2) {
1086 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1087 "<domain>\n");
1088 return false;
1091 if (argc == 2) {
1092 domain = argv[1];
1093 domain_len = strlen(argv[1]) + 1;
1096 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1097 print_pid_string_cb);
1099 buf_len = sizeof(myid)+domain_len;
1100 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1101 if (!buf) {
1102 return false;
1105 memcpy(buf, &myid, sizeof(myid));
1106 memcpy(&buf[sizeof(myid)], domain, domain_len);
1108 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1109 buf, buf_len))
1111 SAFE_FREE(buf);
1112 return false;
1115 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1117 /* No replies were received within the timeout period */
1119 SAFE_FREE(buf);
1120 if (num_replies == 0) {
1121 printf("No replies received\n");
1124 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1126 return num_replies;
1129 static void winbind_validate_cache_cb(struct messaging_context *msg,
1130 void *private_data,
1131 uint32_t msg_type,
1132 struct server_id pid,
1133 DATA_BLOB *data)
1135 char *src_string = server_id_str(NULL, &pid);
1136 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1137 (*(data->data) == 0 ? "" : "NOT "), src_string);
1138 TALLOC_FREE(src_string);
1139 num_replies++;
1142 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1143 struct messaging_context *msg_ctx,
1144 const struct server_id pid,
1145 const int argc, const char **argv)
1147 struct server_id myid;
1149 myid = messaging_server_id(msg_ctx);
1151 if (argc != 1) {
1152 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1153 return False;
1156 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1157 winbind_validate_cache_cb);
1159 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1160 sizeof(myid))) {
1161 return False;
1164 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1166 if (num_replies == 0) {
1167 printf("No replies received\n");
1170 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1172 return num_replies;
1175 static bool do_reload_config(struct tevent_context *ev_ctx,
1176 struct messaging_context *msg_ctx,
1177 const struct server_id pid,
1178 const int argc, const char **argv)
1180 if (argc != 1) {
1181 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1182 return False;
1185 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1188 static bool do_reload_printers(struct tevent_context *ev_ctx,
1189 struct messaging_context *msg_ctx,
1190 const struct server_id pid,
1191 const int argc, const char **argv)
1193 if (argc != 1) {
1194 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1195 return False;
1198 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1201 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1203 fstring unix_name;
1204 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1205 fstrcpy(unix_name, name);
1206 strupper_m(unix_name);
1207 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1208 n->name_type = (unsigned int)type & 0xFF;
1209 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1212 static bool do_nodestatus(struct tevent_context *ev_ctx,
1213 struct messaging_context *msg_ctx,
1214 const struct server_id pid,
1215 const int argc, const char **argv)
1217 struct packet_struct p;
1219 if (argc != 2) {
1220 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1221 return False;
1224 ZERO_STRUCT(p);
1226 p.ip = interpret_addr2(argv[1]);
1227 p.port = 137;
1228 p.packet_type = NMB_PACKET;
1230 p.packet.nmb.header.name_trn_id = 10;
1231 p.packet.nmb.header.opcode = 0;
1232 p.packet.nmb.header.response = False;
1233 p.packet.nmb.header.nm_flags.bcast = False;
1234 p.packet.nmb.header.nm_flags.recursion_available = False;
1235 p.packet.nmb.header.nm_flags.recursion_desired = False;
1236 p.packet.nmb.header.nm_flags.trunc = False;
1237 p.packet.nmb.header.nm_flags.authoritative = False;
1238 p.packet.nmb.header.rcode = 0;
1239 p.packet.nmb.header.qdcount = 1;
1240 p.packet.nmb.header.ancount = 0;
1241 p.packet.nmb.header.nscount = 0;
1242 p.packet.nmb.header.arcount = 0;
1243 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1244 p.packet.nmb.question.question_type = 0x21;
1245 p.packet.nmb.question.question_class = 0x1;
1247 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1250 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1251 struct messaging_context *msg_ctx,
1252 const struct server_id pid,
1253 const int argc, const char **argv)
1255 if (argc != 1) {
1256 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1257 return false;
1259 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1262 /* A list of message type supported */
1264 static const struct {
1265 const char *name; /* Option name */
1266 bool (*fn)(struct tevent_context *ev_ctx,
1267 struct messaging_context *msg_ctx,
1268 const struct server_id pid,
1269 const int argc, const char **argv);
1270 const char *help; /* Short help text */
1271 } msg_types[] = {
1272 { "debug", do_debug, "Set debuglevel" },
1273 { "idmap", do_idmap, "Manipulate idmap cache" },
1274 { "force-election", do_election,
1275 "Force a browse election" },
1276 { "ping", do_ping, "Elicit a response" },
1277 { "profile", do_profile, "" },
1278 { "inject", do_inject_fault,
1279 "Inject a fatal signal into a running smbd"},
1280 { "stacktrace", do_daemon_stack_trace,
1281 "Display a stack trace of a daemon" },
1282 { "profilelevel", do_profilelevel, "" },
1283 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1284 { "printnotify", do_printnotify, "Send a print notify message" },
1285 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1286 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1287 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1288 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1289 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1290 { "dmalloc-mark", do_dmalloc_mark, "" },
1291 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1292 { "shutdown", do_shutdown, "Shut down daemon" },
1293 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1294 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1295 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1296 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1297 { "online", do_winbind_online, "Ask winbind to go into online state"},
1298 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1299 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1300 { "dump-event-list", do_dump_event_list, "Dump event list"},
1301 { "validate-cache" , do_winbind_validate_cache,
1302 "Validate winbind's credential cache" },
1303 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1304 { "notify-cleanup", do_notify_cleanup },
1305 { "noop", do_noop, "Do nothing" },
1306 { NULL }
1309 /* Display usage information */
1311 static void usage(poptContext pc)
1313 int i;
1315 poptPrintHelp(pc, stderr, 0);
1317 fprintf(stderr, "\n");
1318 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1319 "process ID\n");
1321 fprintf(stderr, "\n");
1322 fprintf(stderr, "<message-type> is one of:\n");
1324 for (i = 0; msg_types[i].name; i++)
1325 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1326 msg_types[i].help);
1328 fprintf(stderr, "\n");
1330 exit(1);
1333 /* Return the pid number for a string destination */
1335 static struct server_id parse_dest(struct messaging_context *msg,
1336 const char *dest)
1338 struct server_id result = {-1};
1339 pid_t pid;
1341 /* Zero is a special return value for broadcast to all processes */
1343 if (strequal(dest, "all")) {
1344 return interpret_pid(MSG_BROADCAST_PID_STR);
1347 /* Try self - useful for testing */
1349 if (strequal(dest, "self")) {
1350 return messaging_server_id(msg);
1353 /* Fix winbind typo. */
1354 if (strequal(dest, "winbind")) {
1355 dest = "winbindd";
1358 /* Check for numeric pid number */
1359 result = interpret_pid(dest);
1361 /* Zero isn't valid if not "all". */
1362 if (result.pid && procid_valid(&result)) {
1363 return result;
1366 /* Look up other destinations in pidfile directory */
1368 if ((pid = pidfile_pid(dest)) != 0) {
1369 return pid_to_procid(pid);
1372 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1374 return result;
1377 /* Execute smbcontrol command */
1379 static bool do_command(struct tevent_context *ev_ctx,
1380 struct messaging_context *msg_ctx,
1381 int argc, const char **argv)
1383 const char *dest = argv[0], *command = argv[1];
1384 struct server_id pid;
1385 int i;
1387 /* Check destination */
1389 pid = parse_dest(msg_ctx, dest);
1390 if (!procid_valid(&pid)) {
1391 return False;
1394 /* Check command */
1396 for (i = 0; msg_types[i].name; i++) {
1397 if (strequal(command, msg_types[i].name))
1398 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1399 argc - 1, argv + 1);
1402 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1404 return False;
1407 static void smbcontrol_help(poptContext pc,
1408 enum poptCallbackReason preason,
1409 struct poptOption * poption,
1410 const char * parg,
1411 void * pdata)
1413 if (poption->shortName != '?') {
1414 poptPrintUsage(pc, stdout, 0);
1415 } else {
1416 usage(pc);
1419 exit(0);
1422 struct poptOption help_options[] = {
1423 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1424 NULL, NULL },
1425 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1426 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1427 { NULL }
1430 /* Main program */
1432 int main(int argc, const char **argv)
1434 poptContext pc;
1435 int opt;
1436 struct tevent_context *evt_ctx;
1437 struct messaging_context *msg_ctx;
1439 static struct poptOption long_options[] = {
1440 /* POPT_AUTOHELP */
1441 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1442 0, "Help options:", NULL },
1443 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1444 "Set timeout value in seconds", "TIMEOUT" },
1446 POPT_COMMON_SAMBA
1447 POPT_TABLEEND
1449 TALLOC_CTX *frame = talloc_stackframe();
1450 int ret = 0;
1452 load_case_tables();
1454 setup_logging(argv[0], DEBUG_STDOUT);
1456 /* Parse command line arguments using popt */
1458 pc = poptGetContext(
1459 "smbcontrol", argc, (const char **)argv, long_options, 0);
1461 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1462 "<parameters>");
1464 if (argc == 1)
1465 usage(pc);
1467 while ((opt = poptGetNextOpt(pc)) != -1) {
1468 switch(opt) {
1469 case 't': /* --timeout */
1470 break;
1471 default:
1472 fprintf(stderr, "Invalid option\n");
1473 poptPrintHelp(pc, stderr, 0);
1474 break;
1478 /* We should now have the remaining command line arguments in
1479 argv. The argc parameter should have been decremented to the
1480 correct value in the above switch statement. */
1482 argv = (const char **)poptGetArgs(pc);
1483 argc = 0;
1484 if (argv != NULL) {
1485 while (argv[argc] != NULL) {
1486 argc++;
1490 if (argc <= 1)
1491 usage(pc);
1493 lp_load_global(get_dyn_CONFIGFILE());
1495 /* Need to invert sense of return code -- samba
1496 * routines mostly return True==1 for success, but
1497 * shell needs 0. */
1499 if (!(evt_ctx = tevent_context_init(NULL)) ||
1500 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1501 fprintf(stderr, "could not init messaging context\n");
1502 TALLOC_FREE(frame);
1503 exit(1);
1506 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1507 TALLOC_FREE(frame);
1508 return ret;