VERSION: Disable git snapshots for the 4.0.24 release.
[Samba.git] / source3 / utils / smbcontrol.c
bloba5227820d9c0fee23d145dfd3b0f11ddf54c41c2
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"
35 #include "../lib/util/pidfile.h"
37 #if HAVE_LIBUNWIND_H
38 #include <libunwind.h>
39 #endif
41 #if HAVE_LIBUNWIND_PTRACE_H
42 #include <libunwind-ptrace.h>
43 #endif
45 #if HAVE_SYS_PTRACE_H
46 #include <sys/ptrace.h>
47 #endif
49 /* Default timeout value when waiting for replies (in seconds) */
51 #define DEFAULT_TIMEOUT 10
53 static int timeout = DEFAULT_TIMEOUT;
54 static int num_replies; /* Used by message callback fns */
56 /* Send a message to a destination pid. Zero means broadcast smbd. */
58 static bool send_message(struct messaging_context *msg_ctx,
59 struct server_id pid, int msg_type,
60 const void *buf, int len)
62 bool ret;
63 int n_sent = 0;
65 if (procid_to_pid(&pid) != 0)
66 return NT_STATUS_IS_OK(
67 messaging_send_buf(msg_ctx, pid, msg_type,
68 (const uint8 *)buf, len));
70 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
71 DEBUG(10,("smbcontrol/send_message: broadcast message to "
72 "%d processes\n", n_sent));
74 return ret;
77 static void smbcontrol_timeout(struct tevent_context *event_ctx,
78 struct tevent_timer *te,
79 struct timeval now,
80 void *private_data)
82 bool *timed_out = (bool *)private_data;
83 TALLOC_FREE(te);
84 *timed_out = True;
87 /* Wait for one or more reply messages */
89 static void wait_replies(struct tevent_context *ev_ctx,
90 struct messaging_context *msg_ctx,
91 bool multiple_replies)
93 struct tevent_timer *te;
94 bool timed_out = False;
96 if (!(te = tevent_add_timer(ev_ctx, NULL,
97 timeval_current_ofs(timeout, 0),
98 smbcontrol_timeout, (void *)&timed_out))) {
99 DEBUG(0, ("tevent_add_timer failed\n"));
100 return;
103 while (!timed_out) {
104 int ret;
105 if (num_replies > 0 && !multiple_replies)
106 break;
107 ret = tevent_loop_once(ev_ctx);
108 if (ret != 0) {
109 break;
114 /* Message handler callback that displays the PID and a string on stdout */
116 static void print_pid_string_cb(struct messaging_context *msg,
117 void *private_data,
118 uint32_t msg_type,
119 struct server_id pid,
120 DATA_BLOB *data)
122 char *pidstr;
124 pidstr = server_id_str(talloc_tos(), &pid);
125 printf("PID %s: %.*s", pidstr, (int)data->length,
126 (const char *)data->data);
127 TALLOC_FREE(pidstr);
128 num_replies++;
131 /* Message handler callback that displays a string on stdout */
133 static void print_string_cb(struct messaging_context *msg,
134 void *private_data,
135 uint32_t msg_type,
136 struct server_id pid,
137 DATA_BLOB *data)
139 printf("%*s", (int)data->length, (const char *)data->data);
140 num_replies++;
143 /* Send no message. Useful for testing. */
145 static bool do_noop(struct tevent_context *ev_ctx,
146 struct messaging_context *msg_ctx,
147 const struct server_id pid,
148 const int argc, const char **argv)
150 if (argc != 1) {
151 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
152 return False;
155 /* Move along, nothing to see here */
157 return True;
160 /* Send a debug string */
162 static bool do_debug(struct tevent_context *ev_ctx,
163 struct messaging_context *msg_ctx,
164 const struct server_id pid,
165 const int argc, const char **argv)
167 if (argc != 2) {
168 fprintf(stderr, "Usage: smbcontrol <dest> debug "
169 "<debug-string>\n");
170 return False;
173 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
174 strlen(argv[1]) + 1);
178 static bool do_idmap(struct tevent_context *ev,
179 struct messaging_context *msg_ctx,
180 const struct server_id pid,
181 const int argc, const char **argv)
183 static const char* usage = "Usage: "
184 "smbcontrol <dest> idmap <cmd> [arg]\n"
185 "\tcmd:"
186 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
187 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
188 const char* arg = NULL;
189 int arglen = 0;
190 int msg_type;
192 switch (argc) {
193 case 2:
194 break;
195 case 3:
196 arg = argv[2];
197 arglen = strlen(arg) + 1;
198 break;
199 default:
200 fprintf(stderr, "%s", usage);
201 return false;
204 if (strcmp(argv[1], "delete") == 0) {
205 msg_type = ID_CACHE_DELETE;
207 else if (strcmp(argv[1], "kill") == 0) {
208 msg_type = ID_CACHE_KILL;
210 else if (strcmp(argv[1], "help") == 0) {
211 fprintf(stdout, "%s", usage);
212 return true;
214 else {
215 fprintf(stderr, "%s", usage);
216 return false;
219 return send_message(msg_ctx, pid, msg_type, arg, arglen);
223 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
225 /* Return the name of a process given it's PID. This will only work on Linux,
226 * but that's probably moot since this whole stack tracing implementatino is
227 * Linux-specific anyway.
229 static const char * procname(pid_t pid, char * buf, size_t bufsz)
231 char path[64];
232 FILE * fp;
234 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
235 (unsigned long long)pid);
236 if ((fp = fopen(path, "r")) == NULL) {
237 return NULL;
240 fgets(buf, bufsz, fp);
242 fclose(fp);
243 return buf;
246 static void print_stack_trace(pid_t pid, int * count)
248 void * pinfo = NULL;
249 unw_addr_space_t aspace = NULL;
250 unw_cursor_t cursor;
251 unw_word_t ip, sp;
253 char nbuf[256];
254 unw_word_t off;
256 int ret;
258 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
259 fprintf(stderr,
260 "Failed to attach to process %llu: %s\n",
261 (unsigned long long)pid, strerror(errno));
262 return;
265 /* Wait until the attach is complete. */
266 waitpid(pid, NULL, 0);
268 if (((pinfo = _UPT_create(pid)) == NULL) ||
269 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
270 /* Probably out of memory. */
271 fprintf(stderr,
272 "Unable to initialize stack unwind for process %llu\n",
273 (unsigned long long)pid);
274 goto cleanup;
277 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
278 fprintf(stderr,
279 "Unable to unwind stack for process %llu: %s\n",
280 (unsigned long long)pid, unw_strerror(ret));
281 goto cleanup;
284 if (*count > 0) {
285 printf("\n");
288 if (procname(pid, nbuf, sizeof(nbuf))) {
289 printf("Stack trace for process %llu (%s):\n",
290 (unsigned long long)pid, nbuf);
291 } else {
292 printf("Stack trace for process %llu:\n",
293 (unsigned long long)pid);
296 while (unw_step(&cursor) > 0) {
297 ip = sp = off = 0;
298 unw_get_reg(&cursor, UNW_REG_IP, &ip);
299 unw_get_reg(&cursor, UNW_REG_SP, &sp);
301 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
302 if (ret != 0 && ret != -UNW_ENOMEM) {
303 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
305 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
306 nbuf, (long long)off, (long long)ip,
307 (long long)sp);
310 (*count)++;
312 cleanup:
313 if (aspace) {
314 unw_destroy_addr_space(aspace);
317 if (pinfo) {
318 _UPT_destroy(pinfo);
321 ptrace(PTRACE_DETACH, pid, NULL, NULL);
324 static int stack_trace_server(const struct server_id *id,
325 uint32_t msg_flags,
326 void *priv)
328 if (id->vnn == get_my_vnn()) {
329 print_stack_trace(procid_to_pid(&id->pid), (int *)priv);
331 return 0;
334 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
335 struct messaging_context *msg_ctx,
336 const struct server_id pid,
337 const int argc, const char **argv)
339 pid_t dest;
340 int count = 0;
342 if (argc != 1) {
343 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
344 return False;
347 dest = procid_to_pid(&pid);
349 if (dest != 0) {
350 /* It would be nice to be able to make sure that this PID is
351 * the PID of a smbd/winbind/nmbd process, not some random PID
352 * the user liked the look of. It doesn't seem like it's worth
353 * the effort at the moment, however.
355 print_stack_trace(dest, &count);
356 } else {
357 serverid_traverse_read(stack_trace_server, &count);
360 return True;
363 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
365 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
366 struct messaging_context *msg_ctx,
367 const struct server_id pid,
368 const int argc, const char **argv)
370 fprintf(stderr,
371 "Daemon stack tracing is not supported on this platform\n");
372 return False;
375 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
377 /* Inject a fault (fatal signal) into a running smbd */
379 static bool do_inject_fault(struct tevent_context *ev_ctx,
380 struct messaging_context *msg_ctx,
381 const struct server_id pid,
382 const int argc, const char **argv)
384 if (argc != 2) {
385 fprintf(stderr, "Usage: smbcontrol <dest> inject "
386 "<bus|hup|term|internal|segv>\n");
387 return False;
390 #ifndef DEVELOPER
391 fprintf(stderr, "Fault injection is only available in "
392 "developer builds\n");
393 return False;
394 #else /* DEVELOPER */
396 int sig = 0;
398 if (strcmp(argv[1], "bus") == 0) {
399 sig = SIGBUS;
400 } else if (strcmp(argv[1], "hup") == 0) {
401 sig = SIGHUP;
402 } else if (strcmp(argv[1], "term") == 0) {
403 sig = SIGTERM;
404 } else if (strcmp(argv[1], "segv") == 0) {
405 sig = SIGSEGV;
406 } else if (strcmp(argv[1], "internal") == 0) {
407 /* Force an internal error, ie. an unclean exit. */
408 sig = -1;
409 } else {
410 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
411 return False;
414 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
415 &sig, sizeof(int));
417 #endif /* DEVELOPER */
420 /* Force a browser election */
422 static bool do_election(struct tevent_context *ev_ctx,
423 struct messaging_context *msg_ctx,
424 const struct server_id pid,
425 const int argc, const char **argv)
427 if (argc != 1) {
428 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
429 return False;
432 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
435 /* Ping a samba daemon process */
437 static void pong_cb(struct messaging_context *msg,
438 void *private_data,
439 uint32_t msg_type,
440 struct server_id pid,
441 DATA_BLOB *data)
443 char *src_string = server_id_str(NULL, &pid);
444 printf("PONG from pid %s\n", src_string);
445 TALLOC_FREE(src_string);
446 num_replies++;
449 static bool do_ping(struct tevent_context *ev_ctx,
450 struct messaging_context *msg_ctx,
451 const struct server_id pid,
452 const int argc, const char **argv)
454 if (argc != 1) {
455 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
456 return False;
459 /* Send a message and register our interest in a reply */
461 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
462 return False;
464 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
466 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
468 /* No replies were received within the timeout period */
470 if (num_replies == 0)
471 printf("No replies received\n");
473 messaging_deregister(msg_ctx, MSG_PONG, NULL);
475 return num_replies;
478 /* Set profiling options */
480 static bool do_profile(struct tevent_context *ev_ctx,
481 struct messaging_context *msg_ctx,
482 const struct server_id pid,
483 const int argc, const char **argv)
485 int v;
487 if (argc != 2) {
488 fprintf(stderr, "Usage: smbcontrol <dest> profile "
489 "<off|count|on|flush>\n");
490 return False;
493 if (strcmp(argv[1], "off") == 0) {
494 v = 0;
495 } else if (strcmp(argv[1], "count") == 0) {
496 v = 1;
497 } else if (strcmp(argv[1], "on") == 0) {
498 v = 2;
499 } else if (strcmp(argv[1], "flush") == 0) {
500 v = 3;
501 } else {
502 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
503 return False;
506 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
509 /* Return the profiling level */
511 static void profilelevel_cb(struct messaging_context *msg_ctx,
512 void *private_data,
513 uint32_t msg_type,
514 struct server_id pid,
515 DATA_BLOB *data)
517 int level;
518 const char *s;
520 num_replies++;
522 if (data->length != sizeof(int)) {
523 fprintf(stderr, "invalid message length %ld returned\n",
524 (unsigned long)data->length);
525 return;
528 memcpy(&level, data->data, sizeof(int));
530 switch (level) {
531 case 0:
532 s = "not enabled";
533 break;
534 case 1:
535 s = "off";
536 break;
537 case 3:
538 s = "count only";
539 break;
540 case 7:
541 s = "count and time";
542 break;
543 default:
544 s = "BOGUS";
545 break;
548 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
551 static void profilelevel_rqst(struct messaging_context *msg_ctx,
552 void *private_data,
553 uint32_t msg_type,
554 struct server_id pid,
555 DATA_BLOB *data)
557 int v = 0;
559 /* Send back a dummy reply */
561 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
564 static bool do_profilelevel(struct tevent_context *ev_ctx,
565 struct messaging_context *msg_ctx,
566 const struct server_id pid,
567 const int argc, const char **argv)
569 if (argc != 1) {
570 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
571 return False;
574 /* Send a message and register our interest in a reply */
576 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
577 return False;
579 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
580 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
581 profilelevel_rqst);
583 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
585 /* No replies were received within the timeout period */
587 if (num_replies == 0)
588 printf("No replies received\n");
590 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
592 return num_replies;
595 /* Display debug level settings */
597 static bool do_debuglevel(struct tevent_context *ev_ctx,
598 struct messaging_context *msg_ctx,
599 const struct server_id pid,
600 const int argc, const char **argv)
602 if (argc != 1) {
603 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
604 return False;
607 /* Send a message and register our interest in a reply */
609 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
610 return False;
612 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
614 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
616 /* No replies were received within the timeout period */
618 if (num_replies == 0)
619 printf("No replies received\n");
621 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
623 return num_replies;
626 /* Send a print notify message */
628 static bool do_printnotify(struct tevent_context *ev_ctx,
629 struct messaging_context *msg_ctx,
630 const struct server_id pid,
631 const int argc, const char **argv)
633 const char *cmd;
635 /* Check for subcommand */
637 if (argc == 1) {
638 fprintf(stderr, "Must specify subcommand:\n");
639 fprintf(stderr, "\tqueuepause <printername>\n");
640 fprintf(stderr, "\tqueueresume <printername>\n");
641 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
642 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
643 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
644 fprintf(stderr, "\tprinter <printername> <comment|port|"
645 "driver> <value>\n");
647 return False;
650 cmd = argv[1];
652 if (strcmp(cmd, "queuepause") == 0) {
654 if (argc != 3) {
655 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
656 " queuepause <printername>\n");
657 return False;
660 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
661 PRINTER_STATUS_PAUSED);
663 goto send;
665 } else if (strcmp(cmd, "queueresume") == 0) {
667 if (argc != 3) {
668 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
669 " queuereume <printername>\n");
670 return False;
673 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
674 PRINTER_STATUS_OK);
676 goto send;
678 } else if (strcmp(cmd, "jobpause") == 0) {
679 int jobid;
681 if (argc != 4) {
682 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
683 " jobpause <printername> <unix-jobid>\n");
684 return False;
687 jobid = atoi(argv[3]);
689 notify_job_status_byname(
690 ev_ctx, msg_ctx,
691 argv[2], jobid, JOB_STATUS_PAUSED,
692 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
694 goto send;
696 } else if (strcmp(cmd, "jobresume") == 0) {
697 int jobid;
699 if (argc != 4) {
700 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
701 " jobpause <printername> <unix-jobid>\n");
702 return False;
705 jobid = atoi(argv[3]);
707 notify_job_status_byname(
708 ev_ctx, msg_ctx,
709 argv[2], jobid, JOB_STATUS_QUEUED,
710 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
712 goto send;
714 } else if (strcmp(cmd, "jobdelete") == 0) {
715 int jobid;
717 if (argc != 4) {
718 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
719 " jobpause <printername> <unix-jobid>\n");
720 return False;
723 jobid = atoi(argv[3]);
725 notify_job_status_byname(
726 ev_ctx, msg_ctx,
727 argv[2], jobid, JOB_STATUS_DELETING,
728 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
730 notify_job_status_byname(
731 ev_ctx, msg_ctx,
732 argv[2], jobid, JOB_STATUS_DELETING|
733 JOB_STATUS_DELETED,
734 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
736 goto send;
738 } else if (strcmp(cmd, "printer") == 0) {
739 uint32 attribute;
741 if (argc != 5) {
742 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
743 "printer <printername> <comment|port|driver> "
744 "<value>\n");
745 return False;
748 if (strcmp(argv[3], "comment") == 0) {
749 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
750 } else if (strcmp(argv[3], "port") == 0) {
751 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
752 } else if (strcmp(argv[3], "driver") == 0) {
753 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
754 } else {
755 fprintf(stderr, "Invalid printer command '%s'\n",
756 argv[3]);
757 return False;
760 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
761 discard_const_p(char, argv[4]));
763 goto send;
766 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
767 return False;
769 send:
770 print_notify_send_messages(msg_ctx, 0);
771 return True;
774 /* Close a share */
776 static bool do_closeshare(struct tevent_context *ev_ctx,
777 struct messaging_context *msg_ctx,
778 const struct server_id pid,
779 const int argc, const char **argv)
781 if (argc != 2) {
782 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
783 "<sharename>\n");
784 return False;
787 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
788 strlen(argv[1]) + 1);
791 /* Tell winbindd an IP got dropped */
793 static bool do_ip_dropped(struct tevent_context *ev_ctx,
794 struct messaging_context *msg_ctx,
795 const struct server_id pid,
796 const int argc, const char **argv)
798 if (argc != 2) {
799 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
800 "<ip-address>\n");
801 return False;
804 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
805 strlen(argv[1]) + 1);
808 /* force a blocking lock retry */
810 static bool do_lockretry(struct tevent_context *ev_ctx,
811 struct messaging_context *msg_ctx,
812 const struct server_id pid,
813 const int argc, const char **argv)
815 if (argc != 1) {
816 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
817 return False;
820 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
823 /* force a validation of all brl entries, including re-sends. */
825 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
826 struct messaging_context *msg_ctx,
827 const struct server_id pid,
828 const int argc, const char **argv)
830 if (argc != 1) {
831 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
832 return False;
835 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
838 /* Display talloc pool usage */
840 static bool do_poolusage(struct tevent_context *ev_ctx,
841 struct messaging_context *msg_ctx,
842 const struct server_id pid,
843 const int argc, const char **argv)
845 if (argc != 1) {
846 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
847 return False;
850 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
852 /* Send a message and register our interest in a reply */
854 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
855 return False;
857 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
859 /* No replies were received within the timeout period */
861 if (num_replies == 0)
862 printf("No replies received\n");
864 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
866 return num_replies;
869 /* Perform a dmalloc mark */
871 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
872 struct messaging_context *msg_ctx,
873 const struct server_id pid,
874 const int argc, const char **argv)
876 if (argc != 1) {
877 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
878 return False;
881 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
884 /* Perform a dmalloc changed */
886 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
887 struct messaging_context *msg_ctx,
888 const struct server_id pid,
889 const int argc, const char **argv)
891 if (argc != 1) {
892 fprintf(stderr, "Usage: smbcontrol <dest> "
893 "dmalloc-log-changed\n");
894 return False;
897 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
898 NULL, 0);
901 /* Shutdown a server process */
903 static bool do_shutdown(struct tevent_context *ev_ctx,
904 struct messaging_context *msg_ctx,
905 const struct server_id pid,
906 const int argc, const char **argv)
908 if (argc != 1) {
909 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
910 return False;
913 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
916 /* Notify a driver upgrade */
918 static bool do_drvupgrade(struct tevent_context *ev_ctx,
919 struct messaging_context *msg_ctx,
920 const struct server_id pid,
921 const int argc, const char **argv)
923 if (argc != 2) {
924 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
925 "<driver-name>\n");
926 return False;
929 return send_message(msg_ctx, pid, MSG_PRINTER_DRVUPGRADE, argv[1],
930 strlen(argv[1]) + 1);
933 static bool do_winbind_online(struct tevent_context *ev_ctx,
934 struct messaging_context *msg_ctx,
935 const struct server_id pid,
936 const int argc, const char **argv)
938 TDB_CONTEXT *tdb;
940 if (argc != 1) {
941 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
942 return False;
945 /* Remove the entry in the winbindd_cache tdb to tell a later
946 starting winbindd that we're online. */
948 tdb = tdb_open_log(state_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
949 if (!tdb) {
950 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
951 state_path("winbindd_cache.tdb"));
952 return False;
955 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
956 tdb_close(tdb);
958 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
961 static bool do_winbind_offline(struct tevent_context *ev_ctx,
962 struct messaging_context *msg_ctx,
963 const struct server_id pid,
964 const int argc, const char **argv)
966 TDB_CONTEXT *tdb;
967 bool ret = False;
968 int retry = 0;
970 if (argc != 1) {
971 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
972 return False;
975 /* Create an entry in the winbindd_cache tdb to tell a later
976 starting winbindd that we're offline. We may actually create
977 it here... */
979 tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
980 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
981 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
982 O_RDWR|O_CREAT, 0600);
984 if (!tdb) {
985 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
986 state_path("winbindd_cache.tdb"));
987 return False;
990 /* There's a potential race condition that if a child
991 winbindd detects a domain is online at the same time
992 we're trying to tell it to go offline that it might
993 delete the record we add between us adding it and
994 sending the message. Minimize this by retrying up to
995 5 times. */
997 for (retry = 0; retry < 5; retry++) {
998 TDB_DATA d;
999 uint8 buf[4];
1001 ZERO_STRUCT(d);
1003 SIVAL(buf, 0, time(NULL));
1004 d.dptr = buf;
1005 d.dsize = 4;
1007 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1009 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1010 NULL, 0);
1012 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1013 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1015 if (!d.dptr || d.dsize != 4) {
1016 SAFE_FREE(d.dptr);
1017 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1018 } else {
1019 SAFE_FREE(d.dptr);
1020 break;
1024 tdb_close(tdb);
1025 return ret;
1028 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1029 struct messaging_context *msg_ctx,
1030 const struct server_id pid,
1031 const int argc, const char **argv)
1033 struct server_id myid;
1035 myid = messaging_server_id(msg_ctx);
1037 if (argc != 1) {
1038 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1039 return False;
1042 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1043 print_pid_string_cb);
1045 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1046 sizeof(myid)))
1047 return False;
1049 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1051 /* No replies were received within the timeout period */
1053 if (num_replies == 0)
1054 printf("No replies received\n");
1056 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1058 return num_replies;
1061 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1062 struct messaging_context *msg_ctx,
1063 const struct server_id pid,
1064 const int argc, const char **argv)
1066 if (argc != 1) {
1067 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1068 return False;
1071 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1074 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1075 struct messaging_context *msg_ctx,
1076 const struct server_id pid,
1077 const int argc, const char **argv)
1079 const char *domain = NULL;
1080 int domain_len = 0;
1081 struct server_id myid;
1082 uint8_t *buf = NULL;
1083 int buf_len = 0;
1085 myid = messaging_server_id(msg_ctx);
1087 if (argc < 1 || argc > 2) {
1088 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1089 "<domain>\n");
1090 return false;
1093 if (argc == 2) {
1094 domain = argv[1];
1095 domain_len = strlen(argv[1]) + 1;
1098 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1099 print_pid_string_cb);
1101 buf_len = sizeof(myid)+domain_len;
1102 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1103 if (!buf) {
1104 return false;
1107 memcpy(buf, &myid, sizeof(myid));
1108 memcpy(&buf[sizeof(myid)], domain, domain_len);
1110 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1111 buf, buf_len))
1113 SAFE_FREE(buf);
1114 return false;
1117 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1119 /* No replies were received within the timeout period */
1121 SAFE_FREE(buf);
1122 if (num_replies == 0) {
1123 printf("No replies received\n");
1126 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1128 return num_replies;
1131 static void winbind_validate_cache_cb(struct messaging_context *msg,
1132 void *private_data,
1133 uint32_t msg_type,
1134 struct server_id pid,
1135 DATA_BLOB *data)
1137 char *src_string = server_id_str(NULL, &pid);
1138 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1139 (*(data->data) == 0 ? "" : "NOT "), src_string);
1140 TALLOC_FREE(src_string);
1141 num_replies++;
1144 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1145 struct messaging_context *msg_ctx,
1146 const struct server_id pid,
1147 const int argc, const char **argv)
1149 struct server_id myid;
1151 myid = messaging_server_id(msg_ctx);
1153 if (argc != 1) {
1154 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1155 return False;
1158 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1159 winbind_validate_cache_cb);
1161 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1162 sizeof(myid))) {
1163 return False;
1166 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1168 if (num_replies == 0) {
1169 printf("No replies received\n");
1172 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1174 return num_replies;
1177 static bool do_reload_config(struct tevent_context *ev_ctx,
1178 struct messaging_context *msg_ctx,
1179 const struct server_id pid,
1180 const int argc, const char **argv)
1182 if (argc != 1) {
1183 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1184 return False;
1187 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1190 static bool do_reload_printers(struct tevent_context *ev_ctx,
1191 struct messaging_context *msg_ctx,
1192 const struct server_id pid,
1193 const int argc, const char **argv)
1195 if (argc != 1) {
1196 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1197 return False;
1200 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1203 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1205 fstring unix_name;
1206 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1207 fstrcpy(unix_name, name);
1208 (void)strupper_m(unix_name);
1209 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1210 n->name_type = (unsigned int)type & 0xFF;
1211 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1214 static bool do_nodestatus(struct tevent_context *ev_ctx,
1215 struct messaging_context *msg_ctx,
1216 const struct server_id pid,
1217 const int argc, const char **argv)
1219 struct packet_struct p;
1221 if (argc != 2) {
1222 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1223 return False;
1226 ZERO_STRUCT(p);
1228 p.ip = interpret_addr2(argv[1]);
1229 p.port = 137;
1230 p.packet_type = NMB_PACKET;
1232 p.packet.nmb.header.name_trn_id = 10;
1233 p.packet.nmb.header.opcode = 0;
1234 p.packet.nmb.header.response = False;
1235 p.packet.nmb.header.nm_flags.bcast = False;
1236 p.packet.nmb.header.nm_flags.recursion_available = False;
1237 p.packet.nmb.header.nm_flags.recursion_desired = False;
1238 p.packet.nmb.header.nm_flags.trunc = False;
1239 p.packet.nmb.header.nm_flags.authoritative = False;
1240 p.packet.nmb.header.rcode = 0;
1241 p.packet.nmb.header.qdcount = 1;
1242 p.packet.nmb.header.ancount = 0;
1243 p.packet.nmb.header.nscount = 0;
1244 p.packet.nmb.header.arcount = 0;
1245 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1246 p.packet.nmb.question.question_type = 0x21;
1247 p.packet.nmb.question.question_class = 0x1;
1249 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1252 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1253 struct messaging_context *msg_ctx,
1254 const struct server_id pid,
1255 const int argc, const char **argv)
1257 if (argc != 1) {
1258 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1259 return false;
1261 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1264 /* A list of message type supported */
1266 static const struct {
1267 const char *name; /* Option name */
1268 bool (*fn)(struct tevent_context *ev_ctx,
1269 struct messaging_context *msg_ctx,
1270 const struct server_id pid,
1271 const int argc, const char **argv);
1272 const char *help; /* Short help text */
1273 } msg_types[] = {
1274 { "debug", do_debug, "Set debuglevel" },
1275 { "idmap", do_idmap, "Manipulate idmap cache" },
1276 { "force-election", do_election,
1277 "Force a browse election" },
1278 { "ping", do_ping, "Elicit a response" },
1279 { "profile", do_profile, "" },
1280 { "inject", do_inject_fault,
1281 "Inject a fatal signal into a running smbd"},
1282 { "stacktrace", do_daemon_stack_trace,
1283 "Display a stack trace of a daemon" },
1284 { "profilelevel", do_profilelevel, "" },
1285 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1286 { "printnotify", do_printnotify, "Send a print notify message" },
1287 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1288 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1289 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1290 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1291 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1292 { "dmalloc-mark", do_dmalloc_mark, "" },
1293 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1294 { "shutdown", do_shutdown, "Shut down daemon" },
1295 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1296 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1297 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1298 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1299 { "online", do_winbind_online, "Ask winbind to go into online state"},
1300 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1301 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1302 { "dump-event-list", do_dump_event_list, "Dump event list"},
1303 { "validate-cache" , do_winbind_validate_cache,
1304 "Validate winbind's credential cache" },
1305 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1306 { "notify-cleanup", do_notify_cleanup },
1307 { "noop", do_noop, "Do nothing" },
1308 { NULL }
1311 /* Display usage information */
1313 static void usage(poptContext pc)
1315 int i;
1317 poptPrintHelp(pc, stderr, 0);
1319 fprintf(stderr, "\n");
1320 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1321 "process ID\n");
1323 fprintf(stderr, "\n");
1324 fprintf(stderr, "<message-type> is one of:\n");
1326 for (i = 0; msg_types[i].name; i++)
1327 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1328 msg_types[i].help);
1330 fprintf(stderr, "\n");
1332 exit(1);
1335 /* Return the pid number for a string destination */
1337 static struct server_id parse_dest(struct messaging_context *msg,
1338 const char *dest)
1340 struct server_id result = {-1};
1341 pid_t pid;
1343 /* Zero is a special return value for broadcast to all processes */
1345 if (strequal(dest, "all")) {
1346 return interpret_pid(MSG_BROADCAST_PID_STR);
1349 /* Try self - useful for testing */
1351 if (strequal(dest, "self")) {
1352 return messaging_server_id(msg);
1355 /* Fix winbind typo. */
1356 if (strequal(dest, "winbind")) {
1357 dest = "winbindd";
1360 /* Check for numeric pid number */
1361 result = interpret_pid(dest);
1363 /* Zero isn't valid if not "all". */
1364 if (result.pid && procid_valid(&result)) {
1365 return result;
1368 /* Look up other destinations in pidfile directory */
1370 if ((pid = pidfile_pid(lp_piddir(), dest)) != 0) {
1371 return pid_to_procid(pid);
1374 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1376 return result;
1379 /* Execute smbcontrol command */
1381 static bool do_command(struct tevent_context *ev_ctx,
1382 struct messaging_context *msg_ctx,
1383 int argc, const char **argv)
1385 const char *dest = argv[0], *command = argv[1];
1386 struct server_id pid;
1387 int i;
1389 /* Check destination */
1391 pid = parse_dest(msg_ctx, dest);
1392 if (!procid_valid(&pid)) {
1393 return False;
1396 /* Check command */
1398 for (i = 0; msg_types[i].name; i++) {
1399 if (strequal(command, msg_types[i].name))
1400 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1401 argc - 1, argv + 1);
1404 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1406 return False;
1409 static void smbcontrol_help(poptContext pc,
1410 enum poptCallbackReason preason,
1411 struct poptOption * poption,
1412 const char * parg,
1413 void * pdata)
1415 if (poption->shortName != '?') {
1416 poptPrintUsage(pc, stdout, 0);
1417 } else {
1418 usage(pc);
1421 exit(0);
1424 struct poptOption help_options[] = {
1425 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1426 NULL, NULL },
1427 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1428 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1429 { NULL }
1432 /* Main program */
1434 int main(int argc, const char **argv)
1436 poptContext pc;
1437 int opt;
1438 struct tevent_context *evt_ctx;
1439 struct messaging_context *msg_ctx;
1441 static struct poptOption long_options[] = {
1442 /* POPT_AUTOHELP */
1443 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1444 0, "Help options:", NULL },
1445 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1446 "Set timeout value in seconds", "TIMEOUT" },
1448 POPT_COMMON_SAMBA
1449 POPT_TABLEEND
1451 TALLOC_CTX *frame = talloc_stackframe();
1452 int ret = 0;
1454 load_case_tables();
1456 setup_logging(argv[0], DEBUG_STDOUT);
1458 /* Parse command line arguments using popt */
1460 pc = poptGetContext(
1461 "smbcontrol", argc, (const char **)argv, long_options, 0);
1463 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1464 "<parameters>");
1466 if (argc == 1)
1467 usage(pc);
1469 while ((opt = poptGetNextOpt(pc)) != -1) {
1470 switch(opt) {
1471 case 't': /* --timeout */
1472 break;
1473 default:
1474 fprintf(stderr, "Invalid option\n");
1475 poptPrintHelp(pc, stderr, 0);
1476 break;
1480 /* We should now have the remaining command line arguments in
1481 argv. The argc parameter should have been decremented to the
1482 correct value in the above switch statement. */
1484 argv = (const char **)poptGetArgs(pc);
1485 argc = 0;
1486 if (argv != NULL) {
1487 while (argv[argc] != NULL) {
1488 argc++;
1492 if (argc <= 1)
1493 usage(pc);
1495 lp_load_global(get_dyn_CONFIGFILE());
1497 /* Need to invert sense of return code -- samba
1498 * routines mostly return True==1 for success, but
1499 * shell needs 0. */
1501 if (!(evt_ctx = tevent_context_init(NULL)) ||
1502 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1503 fprintf(stderr, "could not init messaging context\n");
1504 TALLOC_FREE(frame);
1505 exit(1);
1508 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1509 TALLOC_FREE(frame);
1510 return ret;