s3:torture:delete: untangle function call from result check
[Samba.git] / source3 / utils / smbcontrol.c
blob54c5d62c9774038f6e72c341efde0dab8c213d0e
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_connection(const struct connections_key *key,
325 const struct connections_data *crec,
326 void *priv)
328 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
330 return 0;
333 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
334 struct messaging_context *msg_ctx,
335 const struct server_id pid,
336 const int argc, const char **argv)
338 pid_t dest;
339 int count = 0;
341 if (argc != 1) {
342 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
343 return False;
346 dest = procid_to_pid(&pid);
348 if (dest != 0) {
349 /* It would be nice to be able to make sure that this PID is
350 * the PID of a smbd/winbind/nmbd process, not some random PID
351 * the user liked the look of. It doesn't seem like it's worth
352 * the effort at the moment, however.
354 print_stack_trace(dest, &count);
355 } else {
356 connections_forall_read(stack_trace_connection, &count);
359 return True;
362 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
364 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
365 struct messaging_context *msg_ctx,
366 const struct server_id pid,
367 const int argc, const char **argv)
369 fprintf(stderr,
370 "Daemon stack tracing is not supported on this platform\n");
371 return False;
374 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
376 /* Inject a fault (fatal signal) into a running smbd */
378 static bool do_inject_fault(struct tevent_context *ev_ctx,
379 struct messaging_context *msg_ctx,
380 const struct server_id pid,
381 const int argc, const char **argv)
383 if (argc != 2) {
384 fprintf(stderr, "Usage: smbcontrol <dest> inject "
385 "<bus|hup|term|internal|segv>\n");
386 return False;
389 #ifndef DEVELOPER
390 fprintf(stderr, "Fault injection is only available in "
391 "developer builds\n");
392 return False;
393 #else /* DEVELOPER */
395 int sig = 0;
397 if (strcmp(argv[1], "bus") == 0) {
398 sig = SIGBUS;
399 } else if (strcmp(argv[1], "hup") == 0) {
400 sig = SIGHUP;
401 } else if (strcmp(argv[1], "term") == 0) {
402 sig = SIGTERM;
403 } else if (strcmp(argv[1], "segv") == 0) {
404 sig = SIGSEGV;
405 } else if (strcmp(argv[1], "internal") == 0) {
406 /* Force an internal error, ie. an unclean exit. */
407 sig = -1;
408 } else {
409 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
410 return False;
413 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
414 &sig, sizeof(int));
416 #endif /* DEVELOPER */
419 /* Force a browser election */
421 static bool do_election(struct tevent_context *ev_ctx,
422 struct messaging_context *msg_ctx,
423 const struct server_id pid,
424 const int argc, const char **argv)
426 if (argc != 1) {
427 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
428 return False;
431 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
434 /* Ping a samba daemon process */
436 static void pong_cb(struct messaging_context *msg,
437 void *private_data,
438 uint32_t msg_type,
439 struct server_id pid,
440 DATA_BLOB *data)
442 char *src_string = server_id_str(NULL, &pid);
443 printf("PONG from pid %s\n", src_string);
444 TALLOC_FREE(src_string);
445 num_replies++;
448 static bool do_ping(struct tevent_context *ev_ctx,
449 struct messaging_context *msg_ctx,
450 const struct server_id pid,
451 const int argc, const char **argv)
453 if (argc != 1) {
454 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
455 return False;
458 /* Send a message and register our interest in a reply */
460 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
461 return False;
463 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
465 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
467 /* No replies were received within the timeout period */
469 if (num_replies == 0)
470 printf("No replies received\n");
472 messaging_deregister(msg_ctx, MSG_PONG, NULL);
474 return num_replies;
477 /* Set profiling options */
479 static bool do_profile(struct tevent_context *ev_ctx,
480 struct messaging_context *msg_ctx,
481 const struct server_id pid,
482 const int argc, const char **argv)
484 int v;
486 if (argc != 2) {
487 fprintf(stderr, "Usage: smbcontrol <dest> profile "
488 "<off|count|on|flush>\n");
489 return False;
492 if (strcmp(argv[1], "off") == 0) {
493 v = 0;
494 } else if (strcmp(argv[1], "count") == 0) {
495 v = 1;
496 } else if (strcmp(argv[1], "on") == 0) {
497 v = 2;
498 } else if (strcmp(argv[1], "flush") == 0) {
499 v = 3;
500 } else {
501 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
502 return False;
505 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
508 /* Return the profiling level */
510 static void profilelevel_cb(struct messaging_context *msg_ctx,
511 void *private_data,
512 uint32_t msg_type,
513 struct server_id pid,
514 DATA_BLOB *data)
516 int level;
517 const char *s;
519 num_replies++;
521 if (data->length != sizeof(int)) {
522 fprintf(stderr, "invalid message length %ld returned\n",
523 (unsigned long)data->length);
524 return;
527 memcpy(&level, data->data, sizeof(int));
529 switch (level) {
530 case 0:
531 s = "not enabled";
532 break;
533 case 1:
534 s = "off";
535 break;
536 case 3:
537 s = "count only";
538 break;
539 case 7:
540 s = "count and time";
541 break;
542 default:
543 s = "BOGUS";
544 break;
547 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
550 static void profilelevel_rqst(struct messaging_context *msg_ctx,
551 void *private_data,
552 uint32_t msg_type,
553 struct server_id pid,
554 DATA_BLOB *data)
556 int v = 0;
558 /* Send back a dummy reply */
560 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
563 static bool do_profilelevel(struct tevent_context *ev_ctx,
564 struct messaging_context *msg_ctx,
565 const struct server_id pid,
566 const int argc, const char **argv)
568 if (argc != 1) {
569 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
570 return False;
573 /* Send a message and register our interest in a reply */
575 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
576 return False;
578 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
579 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
580 profilelevel_rqst);
582 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
584 /* No replies were received within the timeout period */
586 if (num_replies == 0)
587 printf("No replies received\n");
589 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
591 return num_replies;
594 /* Display debug level settings */
596 static bool do_debuglevel(struct tevent_context *ev_ctx,
597 struct messaging_context *msg_ctx,
598 const struct server_id pid,
599 const int argc, const char **argv)
601 if (argc != 1) {
602 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
603 return False;
606 /* Send a message and register our interest in a reply */
608 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
609 return False;
611 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
613 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
615 /* No replies were received within the timeout period */
617 if (num_replies == 0)
618 printf("No replies received\n");
620 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
622 return num_replies;
625 /* Send a print notify message */
627 static bool do_printnotify(struct tevent_context *ev_ctx,
628 struct messaging_context *msg_ctx,
629 const struct server_id pid,
630 const int argc, const char **argv)
632 const char *cmd;
634 /* Check for subcommand */
636 if (argc == 1) {
637 fprintf(stderr, "Must specify subcommand:\n");
638 fprintf(stderr, "\tqueuepause <printername>\n");
639 fprintf(stderr, "\tqueueresume <printername>\n");
640 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
641 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
642 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
643 fprintf(stderr, "\tprinter <printername> <comment|port|"
644 "driver> <value>\n");
646 return False;
649 cmd = argv[1];
651 if (strcmp(cmd, "queuepause") == 0) {
653 if (argc != 3) {
654 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
655 " queuepause <printername>\n");
656 return False;
659 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
660 PRINTER_STATUS_PAUSED);
662 goto send;
664 } else if (strcmp(cmd, "queueresume") == 0) {
666 if (argc != 3) {
667 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
668 " queuereume <printername>\n");
669 return False;
672 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
673 PRINTER_STATUS_OK);
675 goto send;
677 } else if (strcmp(cmd, "jobpause") == 0) {
678 int jobid;
680 if (argc != 4) {
681 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
682 " jobpause <printername> <unix-jobid>\n");
683 return False;
686 jobid = atoi(argv[3]);
688 notify_job_status_byname(
689 ev_ctx, msg_ctx,
690 argv[2], jobid, JOB_STATUS_PAUSED,
691 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
693 goto send;
695 } else if (strcmp(cmd, "jobresume") == 0) {
696 int jobid;
698 if (argc != 4) {
699 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
700 " jobpause <printername> <unix-jobid>\n");
701 return False;
704 jobid = atoi(argv[3]);
706 notify_job_status_byname(
707 ev_ctx, msg_ctx,
708 argv[2], jobid, JOB_STATUS_QUEUED,
709 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
711 goto send;
713 } else if (strcmp(cmd, "jobdelete") == 0) {
714 int jobid;
716 if (argc != 4) {
717 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
718 " jobpause <printername> <unix-jobid>\n");
719 return False;
722 jobid = atoi(argv[3]);
724 notify_job_status_byname(
725 ev_ctx, msg_ctx,
726 argv[2], jobid, JOB_STATUS_DELETING,
727 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
729 notify_job_status_byname(
730 ev_ctx, msg_ctx,
731 argv[2], jobid, JOB_STATUS_DELETING|
732 JOB_STATUS_DELETED,
733 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
735 goto send;
737 } else if (strcmp(cmd, "printer") == 0) {
738 uint32 attribute;
740 if (argc != 5) {
741 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
742 "printer <printername> <comment|port|driver> "
743 "<value>\n");
744 return False;
747 if (strcmp(argv[3], "comment") == 0) {
748 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
749 } else if (strcmp(argv[3], "port") == 0) {
750 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
751 } else if (strcmp(argv[3], "driver") == 0) {
752 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
753 } else {
754 fprintf(stderr, "Invalid printer command '%s'\n",
755 argv[3]);
756 return False;
759 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
760 discard_const_p(char, argv[4]));
762 goto send;
765 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
766 return False;
768 send:
769 print_notify_send_messages(msg_ctx, 0);
770 return True;
773 /* Close a share */
775 static bool do_closeshare(struct tevent_context *ev_ctx,
776 struct messaging_context *msg_ctx,
777 const struct server_id pid,
778 const int argc, const char **argv)
780 if (argc != 2) {
781 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
782 "<sharename>\n");
783 return False;
786 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
787 strlen(argv[1]) + 1);
790 /* Tell winbindd an IP got dropped */
792 static bool do_ip_dropped(struct tevent_context *ev_ctx,
793 struct messaging_context *msg_ctx,
794 const struct server_id pid,
795 const int argc, const char **argv)
797 if (argc != 2) {
798 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
799 "<ip-address>\n");
800 return False;
803 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
804 strlen(argv[1]) + 1);
807 /* force a blocking lock retry */
809 static bool do_lockretry(struct tevent_context *ev_ctx,
810 struct messaging_context *msg_ctx,
811 const struct server_id pid,
812 const int argc, const char **argv)
814 if (argc != 1) {
815 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
816 return False;
819 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
822 /* force a validation of all brl entries, including re-sends. */
824 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
825 struct messaging_context *msg_ctx,
826 const struct server_id pid,
827 const int argc, const char **argv)
829 if (argc != 1) {
830 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
831 return False;
834 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
837 /* Display talloc pool usage */
839 static bool do_poolusage(struct tevent_context *ev_ctx,
840 struct messaging_context *msg_ctx,
841 const struct server_id pid,
842 const int argc, const char **argv)
844 if (argc != 1) {
845 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
846 return False;
849 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
851 /* Send a message and register our interest in a reply */
853 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
854 return False;
856 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
858 /* No replies were received within the timeout period */
860 if (num_replies == 0)
861 printf("No replies received\n");
863 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
865 return num_replies;
868 /* Perform a dmalloc mark */
870 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
871 struct messaging_context *msg_ctx,
872 const struct server_id pid,
873 const int argc, const char **argv)
875 if (argc != 1) {
876 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
877 return False;
880 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
883 /* Perform a dmalloc changed */
885 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
886 struct messaging_context *msg_ctx,
887 const struct server_id pid,
888 const int argc, const char **argv)
890 if (argc != 1) {
891 fprintf(stderr, "Usage: smbcontrol <dest> "
892 "dmalloc-log-changed\n");
893 return False;
896 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
897 NULL, 0);
900 /* Shutdown a server process */
902 static bool do_shutdown(struct tevent_context *ev_ctx,
903 struct messaging_context *msg_ctx,
904 const struct server_id pid,
905 const int argc, const char **argv)
907 if (argc != 1) {
908 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
909 return False;
912 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
915 /* Notify a driver upgrade */
917 static bool do_drvupgrade(struct tevent_context *ev_ctx,
918 struct messaging_context *msg_ctx,
919 const struct server_id pid,
920 const int argc, const char **argv)
922 if (argc != 2) {
923 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
924 "<driver-name>\n");
925 return False;
928 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
929 strlen(argv[1]) + 1);
932 static bool do_winbind_online(struct tevent_context *ev_ctx,
933 struct messaging_context *msg_ctx,
934 const struct server_id pid,
935 const int argc, const char **argv)
937 TDB_CONTEXT *tdb;
939 if (argc != 1) {
940 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
941 return False;
944 /* Remove the entry in the winbindd_cache tdb to tell a later
945 starting winbindd that we're online. */
947 tdb = tdb_open_log(state_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
948 if (!tdb) {
949 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
950 state_path("winbindd_cache.tdb"));
951 return False;
954 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
955 tdb_close(tdb);
957 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
960 static bool do_winbind_offline(struct tevent_context *ev_ctx,
961 struct messaging_context *msg_ctx,
962 const struct server_id pid,
963 const int argc, const char **argv)
965 TDB_CONTEXT *tdb;
966 bool ret = False;
967 int retry = 0;
969 if (argc != 1) {
970 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
971 return False;
974 /* Create an entry in the winbindd_cache tdb to tell a later
975 starting winbindd that we're offline. We may actually create
976 it here... */
978 tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
979 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
980 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
981 O_RDWR|O_CREAT, 0600);
983 if (!tdb) {
984 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
985 state_path("winbindd_cache.tdb"));
986 return False;
989 /* There's a potential race condition that if a child
990 winbindd detects a domain is online at the same time
991 we're trying to tell it to go offline that it might
992 delete the record we add between us adding it and
993 sending the message. Minimize this by retrying up to
994 5 times. */
996 for (retry = 0; retry < 5; retry++) {
997 TDB_DATA d;
998 uint8 buf[4];
1000 ZERO_STRUCT(d);
1002 SIVAL(buf, 0, time(NULL));
1003 d.dptr = buf;
1004 d.dsize = 4;
1006 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1008 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1009 NULL, 0);
1011 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1012 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1014 if (!d.dptr || d.dsize != 4) {
1015 SAFE_FREE(d.dptr);
1016 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1017 } else {
1018 SAFE_FREE(d.dptr);
1019 break;
1023 tdb_close(tdb);
1024 return ret;
1027 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1028 struct messaging_context *msg_ctx,
1029 const struct server_id pid,
1030 const int argc, const char **argv)
1032 struct server_id myid;
1034 myid = messaging_server_id(msg_ctx);
1036 if (argc != 1) {
1037 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1038 return False;
1041 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1042 print_pid_string_cb);
1044 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1045 sizeof(myid)))
1046 return False;
1048 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1050 /* No replies were received within the timeout period */
1052 if (num_replies == 0)
1053 printf("No replies received\n");
1055 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1057 return num_replies;
1060 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1061 struct messaging_context *msg_ctx,
1062 const struct server_id pid,
1063 const int argc, const char **argv)
1065 if (argc != 1) {
1066 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1067 return False;
1070 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1073 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1074 struct messaging_context *msg_ctx,
1075 const struct server_id pid,
1076 const int argc, const char **argv)
1078 const char *domain = NULL;
1079 int domain_len = 0;
1080 struct server_id myid;
1081 uint8_t *buf = NULL;
1082 int buf_len = 0;
1084 myid = messaging_server_id(msg_ctx);
1086 if (argc < 1 || argc > 2) {
1087 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1088 "<domain>\n");
1089 return false;
1092 if (argc == 2) {
1093 domain = argv[1];
1094 domain_len = strlen(argv[1]) + 1;
1097 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1098 print_pid_string_cb);
1100 buf_len = sizeof(myid)+domain_len;
1101 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1102 if (!buf) {
1103 return false;
1106 memcpy(buf, &myid, sizeof(myid));
1107 memcpy(&buf[sizeof(myid)], domain, domain_len);
1109 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1110 buf, buf_len))
1112 SAFE_FREE(buf);
1113 return false;
1116 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1118 /* No replies were received within the timeout period */
1120 SAFE_FREE(buf);
1121 if (num_replies == 0) {
1122 printf("No replies received\n");
1125 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1127 return num_replies;
1130 static void winbind_validate_cache_cb(struct messaging_context *msg,
1131 void *private_data,
1132 uint32_t msg_type,
1133 struct server_id pid,
1134 DATA_BLOB *data)
1136 char *src_string = server_id_str(NULL, &pid);
1137 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1138 (*(data->data) == 0 ? "" : "NOT "), src_string);
1139 TALLOC_FREE(src_string);
1140 num_replies++;
1143 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1144 struct messaging_context *msg_ctx,
1145 const struct server_id pid,
1146 const int argc, const char **argv)
1148 struct server_id myid;
1150 myid = messaging_server_id(msg_ctx);
1152 if (argc != 1) {
1153 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1154 return False;
1157 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1158 winbind_validate_cache_cb);
1160 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1161 sizeof(myid))) {
1162 return False;
1165 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1167 if (num_replies == 0) {
1168 printf("No replies received\n");
1171 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1173 return num_replies;
1176 static bool do_reload_config(struct tevent_context *ev_ctx,
1177 struct messaging_context *msg_ctx,
1178 const struct server_id pid,
1179 const int argc, const char **argv)
1181 if (argc != 1) {
1182 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1183 return False;
1186 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1189 static bool do_reload_printers(struct tevent_context *ev_ctx,
1190 struct messaging_context *msg_ctx,
1191 const struct server_id pid,
1192 const int argc, const char **argv)
1194 if (argc != 1) {
1195 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1196 return False;
1199 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1202 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1204 fstring unix_name;
1205 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1206 fstrcpy(unix_name, name);
1207 strupper_m(unix_name);
1208 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1209 n->name_type = (unsigned int)type & 0xFF;
1210 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1213 static bool do_nodestatus(struct tevent_context *ev_ctx,
1214 struct messaging_context *msg_ctx,
1215 const struct server_id pid,
1216 const int argc, const char **argv)
1218 struct packet_struct p;
1220 if (argc != 2) {
1221 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1222 return False;
1225 ZERO_STRUCT(p);
1227 p.ip = interpret_addr2(argv[1]);
1228 p.port = 137;
1229 p.packet_type = NMB_PACKET;
1231 p.packet.nmb.header.name_trn_id = 10;
1232 p.packet.nmb.header.opcode = 0;
1233 p.packet.nmb.header.response = False;
1234 p.packet.nmb.header.nm_flags.bcast = False;
1235 p.packet.nmb.header.nm_flags.recursion_available = False;
1236 p.packet.nmb.header.nm_flags.recursion_desired = False;
1237 p.packet.nmb.header.nm_flags.trunc = False;
1238 p.packet.nmb.header.nm_flags.authoritative = False;
1239 p.packet.nmb.header.rcode = 0;
1240 p.packet.nmb.header.qdcount = 1;
1241 p.packet.nmb.header.ancount = 0;
1242 p.packet.nmb.header.nscount = 0;
1243 p.packet.nmb.header.arcount = 0;
1244 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1245 p.packet.nmb.question.question_type = 0x21;
1246 p.packet.nmb.question.question_class = 0x1;
1248 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1251 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1252 struct messaging_context *msg_ctx,
1253 const struct server_id pid,
1254 const int argc, const char **argv)
1256 if (argc != 1) {
1257 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1258 return false;
1260 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1263 /* A list of message type supported */
1265 static const struct {
1266 const char *name; /* Option name */
1267 bool (*fn)(struct tevent_context *ev_ctx,
1268 struct messaging_context *msg_ctx,
1269 const struct server_id pid,
1270 const int argc, const char **argv);
1271 const char *help; /* Short help text */
1272 } msg_types[] = {
1273 { "debug", do_debug, "Set debuglevel" },
1274 { "idmap", do_idmap, "Manipulate idmap cache" },
1275 { "force-election", do_election,
1276 "Force a browse election" },
1277 { "ping", do_ping, "Elicit a response" },
1278 { "profile", do_profile, "" },
1279 { "inject", do_inject_fault,
1280 "Inject a fatal signal into a running smbd"},
1281 { "stacktrace", do_daemon_stack_trace,
1282 "Display a stack trace of a daemon" },
1283 { "profilelevel", do_profilelevel, "" },
1284 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1285 { "printnotify", do_printnotify, "Send a print notify message" },
1286 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1287 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1288 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1289 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1290 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1291 { "dmalloc-mark", do_dmalloc_mark, "" },
1292 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1293 { "shutdown", do_shutdown, "Shut down daemon" },
1294 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1295 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1296 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1297 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1298 { "online", do_winbind_online, "Ask winbind to go into online state"},
1299 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1300 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1301 { "dump-event-list", do_dump_event_list, "Dump event list"},
1302 { "validate-cache" , do_winbind_validate_cache,
1303 "Validate winbind's credential cache" },
1304 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1305 { "notify-cleanup", do_notify_cleanup },
1306 { "noop", do_noop, "Do nothing" },
1307 { NULL }
1310 /* Display usage information */
1312 static void usage(poptContext pc)
1314 int i;
1316 poptPrintHelp(pc, stderr, 0);
1318 fprintf(stderr, "\n");
1319 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1320 "process ID\n");
1322 fprintf(stderr, "\n");
1323 fprintf(stderr, "<message-type> is one of:\n");
1325 for (i = 0; msg_types[i].name; i++)
1326 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1327 msg_types[i].help);
1329 fprintf(stderr, "\n");
1331 exit(1);
1334 /* Return the pid number for a string destination */
1336 static struct server_id parse_dest(struct messaging_context *msg,
1337 const char *dest)
1339 struct server_id result = {-1};
1340 pid_t pid;
1342 /* Zero is a special return value for broadcast to all processes */
1344 if (strequal(dest, "all")) {
1345 return interpret_pid(MSG_BROADCAST_PID_STR);
1348 /* Try self - useful for testing */
1350 if (strequal(dest, "self")) {
1351 return messaging_server_id(msg);
1354 /* Fix winbind typo. */
1355 if (strequal(dest, "winbind")) {
1356 dest = "winbindd";
1359 /* Check for numeric pid number */
1360 result = interpret_pid(dest);
1362 /* Zero isn't valid if not "all". */
1363 if (result.pid && procid_valid(&result)) {
1364 return result;
1367 /* Look up other destinations in pidfile directory */
1369 if ((pid = pidfile_pid(lp_piddir(), dest)) != 0) {
1370 return pid_to_procid(pid);
1373 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1375 return result;
1378 /* Execute smbcontrol command */
1380 static bool do_command(struct tevent_context *ev_ctx,
1381 struct messaging_context *msg_ctx,
1382 int argc, const char **argv)
1384 const char *dest = argv[0], *command = argv[1];
1385 struct server_id pid;
1386 int i;
1388 /* Check destination */
1390 pid = parse_dest(msg_ctx, dest);
1391 if (!procid_valid(&pid)) {
1392 return False;
1395 /* Check command */
1397 for (i = 0; msg_types[i].name; i++) {
1398 if (strequal(command, msg_types[i].name))
1399 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1400 argc - 1, argv + 1);
1403 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1405 return False;
1408 static void smbcontrol_help(poptContext pc,
1409 enum poptCallbackReason preason,
1410 struct poptOption * poption,
1411 const char * parg,
1412 void * pdata)
1414 if (poption->shortName != '?') {
1415 poptPrintUsage(pc, stdout, 0);
1416 } else {
1417 usage(pc);
1420 exit(0);
1423 struct poptOption help_options[] = {
1424 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1425 NULL, NULL },
1426 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1427 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1428 { NULL }
1431 /* Main program */
1433 int main(int argc, const char **argv)
1435 poptContext pc;
1436 int opt;
1437 struct tevent_context *evt_ctx;
1438 struct messaging_context *msg_ctx;
1440 static struct poptOption long_options[] = {
1441 /* POPT_AUTOHELP */
1442 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1443 0, "Help options:", NULL },
1444 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1445 "Set timeout value in seconds", "TIMEOUT" },
1447 POPT_COMMON_SAMBA
1448 POPT_TABLEEND
1450 TALLOC_CTX *frame = talloc_stackframe();
1451 int ret = 0;
1453 load_case_tables();
1455 setup_logging(argv[0], DEBUG_STDOUT);
1457 /* Parse command line arguments using popt */
1459 pc = poptGetContext(
1460 "smbcontrol", argc, (const char **)argv, long_options, 0);
1462 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1463 "<parameters>");
1465 if (argc == 1)
1466 usage(pc);
1468 while ((opt = poptGetNextOpt(pc)) != -1) {
1469 switch(opt) {
1470 case 't': /* --timeout */
1471 break;
1472 default:
1473 fprintf(stderr, "Invalid option\n");
1474 poptPrintHelp(pc, stderr, 0);
1475 break;
1479 /* We should now have the remaining command line arguments in
1480 argv. The argc parameter should have been decremented to the
1481 correct value in the above switch statement. */
1483 argv = (const char **)poptGetArgs(pc);
1484 argc = 0;
1485 if (argv != NULL) {
1486 while (argv[argc] != NULL) {
1487 argc++;
1491 if (argc <= 1)
1492 usage(pc);
1494 lp_load_global(get_dyn_CONFIGFILE());
1496 /* Need to invert sense of return code -- samba
1497 * routines mostly return True==1 for success, but
1498 * shell needs 0. */
1500 if (!(evt_ctx = tevent_context_init(NULL)) ||
1501 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1502 fprintf(stderr, "could not init messaging context\n");
1503 TALLOC_FREE(frame);
1504 exit(1);
1507 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1508 TALLOC_FREE(frame);
1509 return ret;