s3:memcache: remove the idmap-part from memcache
[Samba/vl.git] / source3 / utils / smbcontrol.c
blobedfe98dbf48e9c611f82d241c5ebe9d2d3ca96a8
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 struct server_id myid;
1066 myid = messaging_server_id(msg_ctx);
1068 if (argc != 1) {
1069 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1070 return False;
1073 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1076 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1077 struct messaging_context *msg_ctx,
1078 const struct server_id pid,
1079 const int argc, const char **argv)
1081 const char *domain = NULL;
1082 int domain_len = 0;
1083 struct server_id myid;
1084 uint8_t *buf = NULL;
1085 int buf_len = 0;
1087 myid = messaging_server_id(msg_ctx);
1089 if (argc < 1 || argc > 2) {
1090 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1091 "<domain>\n");
1092 return false;
1095 if (argc == 2) {
1096 domain = argv[1];
1097 domain_len = strlen(argv[1]) + 1;
1100 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1101 print_pid_string_cb);
1103 buf_len = sizeof(myid)+domain_len;
1104 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1105 if (!buf) {
1106 return false;
1109 memcpy(buf, &myid, sizeof(myid));
1110 memcpy(&buf[sizeof(myid)], domain, domain_len);
1112 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1113 buf, buf_len))
1115 SAFE_FREE(buf);
1116 return false;
1119 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1121 /* No replies were received within the timeout period */
1123 SAFE_FREE(buf);
1124 if (num_replies == 0) {
1125 printf("No replies received\n");
1128 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1130 return num_replies;
1133 static void winbind_validate_cache_cb(struct messaging_context *msg,
1134 void *private_data,
1135 uint32_t msg_type,
1136 struct server_id pid,
1137 DATA_BLOB *data)
1139 char *src_string = server_id_str(NULL, &pid);
1140 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1141 (*(data->data) == 0 ? "" : "NOT "), src_string);
1142 TALLOC_FREE(src_string);
1143 num_replies++;
1146 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1147 struct messaging_context *msg_ctx,
1148 const struct server_id pid,
1149 const int argc, const char **argv)
1151 struct server_id myid;
1153 myid = messaging_server_id(msg_ctx);
1155 if (argc != 1) {
1156 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1157 return False;
1160 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1161 winbind_validate_cache_cb);
1163 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1164 sizeof(myid))) {
1165 return False;
1168 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1170 if (num_replies == 0) {
1171 printf("No replies received\n");
1174 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1176 return num_replies;
1179 static bool do_reload_config(struct tevent_context *ev_ctx,
1180 struct messaging_context *msg_ctx,
1181 const struct server_id pid,
1182 const int argc, const char **argv)
1184 if (argc != 1) {
1185 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1186 return False;
1189 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1192 static bool do_reload_printers(struct tevent_context *ev_ctx,
1193 struct messaging_context *msg_ctx,
1194 const struct server_id pid,
1195 const int argc, const char **argv)
1197 if (argc != 1) {
1198 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1199 return False;
1202 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1205 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1207 fstring unix_name;
1208 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1209 fstrcpy(unix_name, name);
1210 strupper_m(unix_name);
1211 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1212 n->name_type = (unsigned int)type & 0xFF;
1213 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1216 static bool do_nodestatus(struct tevent_context *ev_ctx,
1217 struct messaging_context *msg_ctx,
1218 const struct server_id pid,
1219 const int argc, const char **argv)
1221 struct packet_struct p;
1223 if (argc != 2) {
1224 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1225 return False;
1228 ZERO_STRUCT(p);
1230 p.ip = interpret_addr2(argv[1]);
1231 p.port = 137;
1232 p.packet_type = NMB_PACKET;
1234 p.packet.nmb.header.name_trn_id = 10;
1235 p.packet.nmb.header.opcode = 0;
1236 p.packet.nmb.header.response = False;
1237 p.packet.nmb.header.nm_flags.bcast = False;
1238 p.packet.nmb.header.nm_flags.recursion_available = False;
1239 p.packet.nmb.header.nm_flags.recursion_desired = False;
1240 p.packet.nmb.header.nm_flags.trunc = False;
1241 p.packet.nmb.header.nm_flags.authoritative = False;
1242 p.packet.nmb.header.rcode = 0;
1243 p.packet.nmb.header.qdcount = 1;
1244 p.packet.nmb.header.ancount = 0;
1245 p.packet.nmb.header.nscount = 0;
1246 p.packet.nmb.header.arcount = 0;
1247 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1248 p.packet.nmb.question.question_type = 0x21;
1249 p.packet.nmb.question.question_class = 0x1;
1251 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1254 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1255 struct messaging_context *msg_ctx,
1256 const struct server_id pid,
1257 const int argc, const char **argv)
1259 if (argc != 1) {
1260 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1261 return false;
1263 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1266 /* A list of message type supported */
1268 static const struct {
1269 const char *name; /* Option name */
1270 bool (*fn)(struct tevent_context *ev_ctx,
1271 struct messaging_context *msg_ctx,
1272 const struct server_id pid,
1273 const int argc, const char **argv);
1274 const char *help; /* Short help text */
1275 } msg_types[] = {
1276 { "debug", do_debug, "Set debuglevel" },
1277 { "idmap", do_idmap, "Manipulate idmap cache" },
1278 { "force-election", do_election,
1279 "Force a browse election" },
1280 { "ping", do_ping, "Elicit a response" },
1281 { "profile", do_profile, "" },
1282 { "inject", do_inject_fault,
1283 "Inject a fatal signal into a running smbd"},
1284 { "stacktrace", do_daemon_stack_trace,
1285 "Display a stack trace of a daemon" },
1286 { "profilelevel", do_profilelevel, "" },
1287 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1288 { "printnotify", do_printnotify, "Send a print notify message" },
1289 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1290 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1291 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1292 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1293 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1294 { "dmalloc-mark", do_dmalloc_mark, "" },
1295 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1296 { "shutdown", do_shutdown, "Shut down daemon" },
1297 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1298 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1299 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1300 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1301 { "online", do_winbind_online, "Ask winbind to go into online state"},
1302 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1303 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1304 { "dump-event-list", do_dump_event_list, "Dump event list"},
1305 { "validate-cache" , do_winbind_validate_cache,
1306 "Validate winbind's credential cache" },
1307 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1308 { "notify-cleanup", do_notify_cleanup },
1309 { "noop", do_noop, "Do nothing" },
1310 { NULL }
1313 /* Display usage information */
1315 static void usage(poptContext pc)
1317 int i;
1319 poptPrintHelp(pc, stderr, 0);
1321 fprintf(stderr, "\n");
1322 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1323 "process ID\n");
1325 fprintf(stderr, "\n");
1326 fprintf(stderr, "<message-type> is one of:\n");
1328 for (i = 0; msg_types[i].name; i++)
1329 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1330 msg_types[i].help);
1332 fprintf(stderr, "\n");
1334 exit(1);
1337 /* Return the pid number for a string destination */
1339 static struct server_id parse_dest(struct messaging_context *msg,
1340 const char *dest)
1342 struct server_id result = {-1};
1343 pid_t pid;
1345 /* Zero is a special return value for broadcast to all processes */
1347 if (strequal(dest, "all")) {
1348 return interpret_pid(MSG_BROADCAST_PID_STR);
1351 /* Try self - useful for testing */
1353 if (strequal(dest, "self")) {
1354 return messaging_server_id(msg);
1357 /* Fix winbind typo. */
1358 if (strequal(dest, "winbind")) {
1359 dest = "winbindd";
1362 /* Check for numeric pid number */
1363 result = interpret_pid(dest);
1365 /* Zero isn't valid if not "all". */
1366 if (result.pid && procid_valid(&result)) {
1367 return result;
1370 /* Look up other destinations in pidfile directory */
1372 if ((pid = pidfile_pid(dest)) != 0) {
1373 return pid_to_procid(pid);
1376 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1378 return result;
1381 /* Execute smbcontrol command */
1383 static bool do_command(struct tevent_context *ev_ctx,
1384 struct messaging_context *msg_ctx,
1385 int argc, const char **argv)
1387 const char *dest = argv[0], *command = argv[1];
1388 struct server_id pid;
1389 int i;
1391 /* Check destination */
1393 pid = parse_dest(msg_ctx, dest);
1394 if (!procid_valid(&pid)) {
1395 return False;
1398 /* Check command */
1400 for (i = 0; msg_types[i].name; i++) {
1401 if (strequal(command, msg_types[i].name))
1402 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1403 argc - 1, argv + 1);
1406 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1408 return False;
1411 static void smbcontrol_help(poptContext pc,
1412 enum poptCallbackReason preason,
1413 struct poptOption * poption,
1414 const char * parg,
1415 void * pdata)
1417 if (poption->shortName != '?') {
1418 poptPrintUsage(pc, stdout, 0);
1419 } else {
1420 usage(pc);
1423 exit(0);
1426 struct poptOption help_options[] = {
1427 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1428 NULL, NULL },
1429 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1430 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1431 { NULL }
1434 /* Main program */
1436 int main(int argc, const char **argv)
1438 poptContext pc;
1439 int opt;
1440 struct tevent_context *evt_ctx;
1441 struct messaging_context *msg_ctx;
1443 static struct poptOption long_options[] = {
1444 /* POPT_AUTOHELP */
1445 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1446 0, "Help options:", NULL },
1447 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1448 "Set timeout value in seconds", "TIMEOUT" },
1450 POPT_COMMON_SAMBA
1451 POPT_TABLEEND
1453 TALLOC_CTX *frame = talloc_stackframe();
1454 int ret = 0;
1456 load_case_tables();
1458 setup_logging(argv[0], DEBUG_STDOUT);
1460 /* Parse command line arguments using popt */
1462 pc = poptGetContext(
1463 "smbcontrol", argc, (const char **)argv, long_options, 0);
1465 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1466 "<parameters>");
1468 if (argc == 1)
1469 usage(pc);
1471 while ((opt = poptGetNextOpt(pc)) != -1) {
1472 switch(opt) {
1473 case 't': /* --timeout */
1474 break;
1475 default:
1476 fprintf(stderr, "Invalid option\n");
1477 poptPrintHelp(pc, stderr, 0);
1478 break;
1482 /* We should now have the remaining command line arguments in
1483 argv. The argc parameter should have been decremented to the
1484 correct value in the above switch statement. */
1486 argv = (const char **)poptGetArgs(pc);
1487 argc = 0;
1488 if (argv != NULL) {
1489 while (argv[argc] != NULL) {
1490 argc++;
1494 if (argc <= 1)
1495 usage(pc);
1497 lp_load_global(get_dyn_CONFIGFILE());
1499 /* Need to invert sense of return code -- samba
1500 * routines mostly return True==1 for success, but
1501 * shell needs 0. */
1503 if (!(evt_ctx = tevent_context_init(NULL)) ||
1504 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1505 fprintf(stderr, "could not init messaging context\n");
1506 TALLOC_FREE(frame);
1507 exit(1);
1510 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1511 TALLOC_FREE(frame);
1512 return ret;