smbcontrol: Fix the build with libunwind
[Samba/gebeck_regimport.git] / source3 / utils / smbcontrol.c
blob8a690566e70903df87941310eef81d4ed61518f6
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 te = tevent_add_timer(ev_ctx, NULL,
97 timeval_current_ofs(timeout, 0),
98 smbcontrol_timeout, (void *)&timed_out);
99 if (te == NULL) {
100 DEBUG(0, ("tevent_add_timer failed\n"));
101 return;
104 while (!timed_out) {
105 int ret;
106 if (num_replies > 0 && !multiple_replies)
107 break;
108 ret = tevent_loop_once(ev_ctx);
109 if (ret != 0) {
110 break;
115 /* Message handler callback that displays the PID and a string on stdout */
117 static void print_pid_string_cb(struct messaging_context *msg,
118 void *private_data,
119 uint32_t msg_type,
120 struct server_id pid,
121 DATA_BLOB *data)
123 char *pidstr;
125 pidstr = server_id_str(talloc_tos(), &pid);
126 printf("PID %s: %.*s", pidstr, (int)data->length,
127 (const char *)data->data);
128 TALLOC_FREE(pidstr);
129 num_replies++;
132 /* Message handler callback that displays a string on stdout */
134 static void print_string_cb(struct messaging_context *msg,
135 void *private_data,
136 uint32_t msg_type,
137 struct server_id pid,
138 DATA_BLOB *data)
140 printf("%*s", (int)data->length, (const char *)data->data);
141 num_replies++;
144 /* Send no message. Useful for testing. */
146 static bool do_noop(struct tevent_context *ev_ctx,
147 struct messaging_context *msg_ctx,
148 const struct server_id pid,
149 const int argc, const char **argv)
151 if (argc != 1) {
152 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
153 return False;
156 /* Move along, nothing to see here */
158 return True;
161 /* Send a debug string */
163 static bool do_debug(struct tevent_context *ev_ctx,
164 struct messaging_context *msg_ctx,
165 const struct server_id pid,
166 const int argc, const char **argv)
168 if (argc != 2) {
169 fprintf(stderr, "Usage: smbcontrol <dest> debug "
170 "<debug-string>\n");
171 return False;
174 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
175 strlen(argv[1]) + 1);
179 static bool do_idmap(struct tevent_context *ev,
180 struct messaging_context *msg_ctx,
181 const struct server_id pid,
182 const int argc, const char **argv)
184 static const char* usage = "Usage: "
185 "smbcontrol <dest> idmap <cmd> [arg]\n"
186 "\tcmd:"
187 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
188 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
189 const char* arg = NULL;
190 int arglen = 0;
191 int msg_type;
193 switch (argc) {
194 case 2:
195 break;
196 case 3:
197 arg = argv[2];
198 arglen = strlen(arg) + 1;
199 break;
200 default:
201 fprintf(stderr, "%s", usage);
202 return false;
205 if (strcmp(argv[1], "delete") == 0) {
206 msg_type = ID_CACHE_DELETE;
208 else if (strcmp(argv[1], "kill") == 0) {
209 msg_type = ID_CACHE_KILL;
211 else if (strcmp(argv[1], "help") == 0) {
212 fprintf(stdout, "%s", usage);
213 return true;
215 else {
216 fprintf(stderr, "%s", usage);
217 return false;
220 return send_message(msg_ctx, pid, msg_type, arg, arglen);
224 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
226 /* Return the name of a process given it's PID. This will only work on Linux,
227 * but that's probably moot since this whole stack tracing implementatino is
228 * Linux-specific anyway.
230 static const char * procname(pid_t pid, char * buf, size_t bufsz)
232 char path[64];
233 FILE * fp;
235 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
236 (unsigned long long)pid);
237 if ((fp = fopen(path, "r")) == NULL) {
238 return NULL;
241 fgets(buf, bufsz, fp);
243 fclose(fp);
244 return buf;
247 static void print_stack_trace(pid_t pid, int * count)
249 void * pinfo = NULL;
250 unw_addr_space_t aspace = NULL;
251 unw_cursor_t cursor;
252 unw_word_t ip, sp;
254 char nbuf[256];
255 unw_word_t off;
257 int ret;
259 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
260 fprintf(stderr,
261 "Failed to attach to process %llu: %s\n",
262 (unsigned long long)pid, strerror(errno));
263 return;
266 /* Wait until the attach is complete. */
267 waitpid(pid, NULL, 0);
269 if (((pinfo = _UPT_create(pid)) == NULL) ||
270 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
271 /* Probably out of memory. */
272 fprintf(stderr,
273 "Unable to initialize stack unwind for process %llu\n",
274 (unsigned long long)pid);
275 goto cleanup;
278 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
279 fprintf(stderr,
280 "Unable to unwind stack for process %llu: %s\n",
281 (unsigned long long)pid, unw_strerror(ret));
282 goto cleanup;
285 if (*count > 0) {
286 printf("\n");
289 if (procname(pid, nbuf, sizeof(nbuf))) {
290 printf("Stack trace for process %llu (%s):\n",
291 (unsigned long long)pid, nbuf);
292 } else {
293 printf("Stack trace for process %llu:\n",
294 (unsigned long long)pid);
297 while (unw_step(&cursor) > 0) {
298 ip = sp = off = 0;
299 unw_get_reg(&cursor, UNW_REG_IP, &ip);
300 unw_get_reg(&cursor, UNW_REG_SP, &sp);
302 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
303 if (ret != 0 && ret != -UNW_ENOMEM) {
304 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
306 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
307 nbuf, (long long)off, (long long)ip,
308 (long long)sp);
311 (*count)++;
313 cleanup:
314 if (aspace) {
315 unw_destroy_addr_space(aspace);
318 if (pinfo) {
319 _UPT_destroy(pinfo);
322 ptrace(PTRACE_DETACH, pid, NULL, NULL);
325 static int stack_trace_server(const struct server_id *id,
326 uint32_t msg_flags,
327 void *priv)
329 if (id->vnn == get_my_vnn()) {
330 print_stack_trace(procid_to_pid(id), (int *)priv);
332 return 0;
335 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
336 struct messaging_context *msg_ctx,
337 const struct server_id pid,
338 const int argc, const char **argv)
340 pid_t dest;
341 int count = 0;
343 if (argc != 1) {
344 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
345 return False;
348 dest = procid_to_pid(&pid);
350 if (dest != 0) {
351 /* It would be nice to be able to make sure that this PID is
352 * the PID of a smbd/winbind/nmbd process, not some random PID
353 * the user liked the look of. It doesn't seem like it's worth
354 * the effort at the moment, however.
356 print_stack_trace(dest, &count);
357 } else {
358 serverid_traverse_read(stack_trace_server, &count);
361 return True;
364 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
366 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
367 struct messaging_context *msg_ctx,
368 const struct server_id pid,
369 const int argc, const char **argv)
371 fprintf(stderr,
372 "Daemon stack tracing is not supported on this platform\n");
373 return False;
376 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
378 /* Inject a fault (fatal signal) into a running smbd */
380 static bool do_inject_fault(struct tevent_context *ev_ctx,
381 struct messaging_context *msg_ctx,
382 const struct server_id pid,
383 const int argc, const char **argv)
385 if (argc != 2) {
386 fprintf(stderr, "Usage: smbcontrol <dest> inject "
387 "<bus|hup|term|internal|segv>\n");
388 return False;
391 #ifndef DEVELOPER
392 fprintf(stderr, "Fault injection is only available in "
393 "developer builds\n");
394 return False;
395 #else /* DEVELOPER */
397 int sig = 0;
399 if (strcmp(argv[1], "bus") == 0) {
400 sig = SIGBUS;
401 } else if (strcmp(argv[1], "hup") == 0) {
402 sig = SIGHUP;
403 } else if (strcmp(argv[1], "term") == 0) {
404 sig = SIGTERM;
405 } else if (strcmp(argv[1], "segv") == 0) {
406 sig = SIGSEGV;
407 } else if (strcmp(argv[1], "internal") == 0) {
408 /* Force an internal error, ie. an unclean exit. */
409 sig = -1;
410 } else {
411 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
412 return False;
415 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
416 &sig, sizeof(int));
418 #endif /* DEVELOPER */
421 /* Force a browser election */
423 static bool do_election(struct tevent_context *ev_ctx,
424 struct messaging_context *msg_ctx,
425 const struct server_id pid,
426 const int argc, const char **argv)
428 if (argc != 1) {
429 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
430 return False;
433 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
436 /* Ping a samba daemon process */
438 static void pong_cb(struct messaging_context *msg,
439 void *private_data,
440 uint32_t msg_type,
441 struct server_id pid,
442 DATA_BLOB *data)
444 char *src_string = server_id_str(NULL, &pid);
445 printf("PONG from pid %s\n", src_string);
446 TALLOC_FREE(src_string);
447 num_replies++;
450 static bool do_ping(struct tevent_context *ev_ctx,
451 struct messaging_context *msg_ctx,
452 const struct server_id pid,
453 const int argc, const char **argv)
455 if (argc != 1) {
456 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
457 return False;
460 /* Send a message and register our interest in a reply */
462 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
463 return False;
465 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
467 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
469 /* No replies were received within the timeout period */
471 if (num_replies == 0)
472 printf("No replies received\n");
474 messaging_deregister(msg_ctx, MSG_PONG, NULL);
476 return num_replies;
479 /* Set profiling options */
481 static bool do_profile(struct tevent_context *ev_ctx,
482 struct messaging_context *msg_ctx,
483 const struct server_id pid,
484 const int argc, const char **argv)
486 int v;
488 if (argc != 2) {
489 fprintf(stderr, "Usage: smbcontrol <dest> profile "
490 "<off|count|on|flush>\n");
491 return False;
494 if (strcmp(argv[1], "off") == 0) {
495 v = 0;
496 } else if (strcmp(argv[1], "count") == 0) {
497 v = 1;
498 } else if (strcmp(argv[1], "on") == 0) {
499 v = 2;
500 } else if (strcmp(argv[1], "flush") == 0) {
501 v = 3;
502 } else {
503 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
504 return False;
507 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
510 /* Return the profiling level */
512 static void profilelevel_cb(struct messaging_context *msg_ctx,
513 void *private_data,
514 uint32_t msg_type,
515 struct server_id pid,
516 DATA_BLOB *data)
518 int level;
519 const char *s;
521 num_replies++;
523 if (data->length != sizeof(int)) {
524 fprintf(stderr, "invalid message length %ld returned\n",
525 (unsigned long)data->length);
526 return;
529 memcpy(&level, data->data, sizeof(int));
531 switch (level) {
532 case 0:
533 s = "not enabled";
534 break;
535 case 1:
536 s = "off";
537 break;
538 case 3:
539 s = "count only";
540 break;
541 case 7:
542 s = "count and time";
543 break;
544 default:
545 s = "BOGUS";
546 break;
549 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
552 static void profilelevel_rqst(struct messaging_context *msg_ctx,
553 void *private_data,
554 uint32_t msg_type,
555 struct server_id pid,
556 DATA_BLOB *data)
558 int v = 0;
560 /* Send back a dummy reply */
562 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
565 static bool do_profilelevel(struct tevent_context *ev_ctx,
566 struct messaging_context *msg_ctx,
567 const struct server_id pid,
568 const int argc, const char **argv)
570 if (argc != 1) {
571 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
572 return False;
575 /* Send a message and register our interest in a reply */
577 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
578 return False;
580 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
581 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
582 profilelevel_rqst);
584 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
586 /* No replies were received within the timeout period */
588 if (num_replies == 0)
589 printf("No replies received\n");
591 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
593 return num_replies;
596 /* Display debug level settings */
598 static bool do_debuglevel(struct tevent_context *ev_ctx,
599 struct messaging_context *msg_ctx,
600 const struct server_id pid,
601 const int argc, const char **argv)
603 if (argc != 1) {
604 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
605 return False;
608 /* Send a message and register our interest in a reply */
610 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
611 return False;
613 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
615 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
617 /* No replies were received within the timeout period */
619 if (num_replies == 0)
620 printf("No replies received\n");
622 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
624 return num_replies;
627 /* Send a print notify message */
629 static bool do_printnotify(struct tevent_context *ev_ctx,
630 struct messaging_context *msg_ctx,
631 const struct server_id pid,
632 const int argc, const char **argv)
634 const char *cmd;
636 /* Check for subcommand */
638 if (argc == 1) {
639 fprintf(stderr, "Must specify subcommand:\n");
640 fprintf(stderr, "\tqueuepause <printername>\n");
641 fprintf(stderr, "\tqueueresume <printername>\n");
642 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
643 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
644 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
645 fprintf(stderr, "\tprinter <printername> <comment|port|"
646 "driver> <value>\n");
648 return False;
651 cmd = argv[1];
653 if (strcmp(cmd, "queuepause") == 0) {
655 if (argc != 3) {
656 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
657 " queuepause <printername>\n");
658 return False;
661 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
662 PRINTER_STATUS_PAUSED);
664 goto send;
666 } else if (strcmp(cmd, "queueresume") == 0) {
668 if (argc != 3) {
669 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
670 " queuereume <printername>\n");
671 return False;
674 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
675 PRINTER_STATUS_OK);
677 goto send;
679 } else if (strcmp(cmd, "jobpause") == 0) {
680 int jobid;
682 if (argc != 4) {
683 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
684 " jobpause <printername> <unix-jobid>\n");
685 return False;
688 jobid = atoi(argv[3]);
690 notify_job_status_byname(
691 ev_ctx, msg_ctx,
692 argv[2], jobid, JOB_STATUS_PAUSED,
693 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
695 goto send;
697 } else if (strcmp(cmd, "jobresume") == 0) {
698 int jobid;
700 if (argc != 4) {
701 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
702 " jobpause <printername> <unix-jobid>\n");
703 return False;
706 jobid = atoi(argv[3]);
708 notify_job_status_byname(
709 ev_ctx, msg_ctx,
710 argv[2], jobid, JOB_STATUS_QUEUED,
711 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
713 goto send;
715 } else if (strcmp(cmd, "jobdelete") == 0) {
716 int jobid;
718 if (argc != 4) {
719 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
720 " jobpause <printername> <unix-jobid>\n");
721 return False;
724 jobid = atoi(argv[3]);
726 notify_job_status_byname(
727 ev_ctx, msg_ctx,
728 argv[2], jobid, JOB_STATUS_DELETING,
729 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
731 notify_job_status_byname(
732 ev_ctx, msg_ctx,
733 argv[2], jobid, JOB_STATUS_DELETING|
734 JOB_STATUS_DELETED,
735 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
737 goto send;
739 } else if (strcmp(cmd, "printer") == 0) {
740 uint32 attribute;
742 if (argc != 5) {
743 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
744 "printer <printername> <comment|port|driver> "
745 "<value>\n");
746 return False;
749 if (strcmp(argv[3], "comment") == 0) {
750 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
751 } else if (strcmp(argv[3], "port") == 0) {
752 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
753 } else if (strcmp(argv[3], "driver") == 0) {
754 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
755 } else {
756 fprintf(stderr, "Invalid printer command '%s'\n",
757 argv[3]);
758 return False;
761 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
762 discard_const_p(char, argv[4]));
764 goto send;
767 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
768 return False;
770 send:
771 print_notify_send_messages(msg_ctx, 0);
772 return True;
775 /* Close a share */
777 static bool do_closeshare(struct tevent_context *ev_ctx,
778 struct messaging_context *msg_ctx,
779 const struct server_id pid,
780 const int argc, const char **argv)
782 if (argc != 2) {
783 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
784 "<sharename>\n");
785 return False;
788 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
789 strlen(argv[1]) + 1);
792 /* Tell winbindd an IP got dropped */
794 static bool do_ip_dropped(struct tevent_context *ev_ctx,
795 struct messaging_context *msg_ctx,
796 const struct server_id pid,
797 const int argc, const char **argv)
799 if (argc != 2) {
800 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
801 "<ip-address>\n");
802 return False;
805 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
806 strlen(argv[1]) + 1);
809 /* force a blocking lock retry */
811 static bool do_lockretry(struct tevent_context *ev_ctx,
812 struct messaging_context *msg_ctx,
813 const struct server_id pid,
814 const int argc, const char **argv)
816 if (argc != 1) {
817 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
818 return False;
821 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
824 /* force a validation of all brl entries, including re-sends. */
826 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
827 struct messaging_context *msg_ctx,
828 const struct server_id pid,
829 const int argc, const char **argv)
831 if (argc != 1) {
832 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
833 return False;
836 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
839 /* Display talloc pool usage */
841 static bool do_poolusage(struct tevent_context *ev_ctx,
842 struct messaging_context *msg_ctx,
843 const struct server_id pid,
844 const int argc, const char **argv)
846 if (argc != 1) {
847 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
848 return False;
851 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
853 /* Send a message and register our interest in a reply */
855 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
856 return False;
858 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
860 /* No replies were received within the timeout period */
862 if (num_replies == 0)
863 printf("No replies received\n");
865 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
867 return num_replies;
870 /* Perform a dmalloc mark */
872 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
873 struct messaging_context *msg_ctx,
874 const struct server_id pid,
875 const int argc, const char **argv)
877 if (argc != 1) {
878 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
879 return False;
882 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
885 /* Perform a dmalloc changed */
887 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
888 struct messaging_context *msg_ctx,
889 const struct server_id pid,
890 const int argc, const char **argv)
892 if (argc != 1) {
893 fprintf(stderr, "Usage: smbcontrol <dest> "
894 "dmalloc-log-changed\n");
895 return False;
898 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
899 NULL, 0);
902 /* Shutdown a server process */
904 static bool do_shutdown(struct tevent_context *ev_ctx,
905 struct messaging_context *msg_ctx,
906 const struct server_id pid,
907 const int argc, const char **argv)
909 if (argc != 1) {
910 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
911 return False;
914 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
917 /* Notify a driver upgrade */
919 static bool do_drvupgrade(struct tevent_context *ev_ctx,
920 struct messaging_context *msg_ctx,
921 const struct server_id pid,
922 const int argc, const char **argv)
924 if (argc != 2) {
925 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
926 "<driver-name>\n");
927 return False;
930 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
931 strlen(argv[1]) + 1);
934 static bool do_winbind_online(struct tevent_context *ev_ctx,
935 struct messaging_context *msg_ctx,
936 const struct server_id pid,
937 const int argc, const char **argv)
939 TDB_CONTEXT *tdb;
941 if (argc != 1) {
942 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
943 return False;
946 /* Remove the entry in the winbindd_cache tdb to tell a later
947 starting winbindd that we're online. */
949 tdb = tdb_open_log(state_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
950 if (!tdb) {
951 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
952 state_path("winbindd_cache.tdb"));
953 return False;
956 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
957 tdb_close(tdb);
959 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
962 static bool do_winbind_offline(struct tevent_context *ev_ctx,
963 struct messaging_context *msg_ctx,
964 const struct server_id pid,
965 const int argc, const char **argv)
967 TDB_CONTEXT *tdb;
968 bool ret = False;
969 int retry = 0;
971 if (argc != 1) {
972 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
973 return False;
976 /* Create an entry in the winbindd_cache tdb to tell a later
977 starting winbindd that we're offline. We may actually create
978 it here... */
980 tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
981 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
982 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
983 O_RDWR|O_CREAT, 0600);
985 if (!tdb) {
986 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
987 state_path("winbindd_cache.tdb"));
988 return False;
991 /* There's a potential race condition that if a child
992 winbindd detects a domain is online at the same time
993 we're trying to tell it to go offline that it might
994 delete the record we add between us adding it and
995 sending the message. Minimize this by retrying up to
996 5 times. */
998 for (retry = 0; retry < 5; retry++) {
999 TDB_DATA d;
1000 uint8 buf[4];
1002 ZERO_STRUCT(d);
1004 SIVAL(buf, 0, time(NULL));
1005 d.dptr = buf;
1006 d.dsize = 4;
1008 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1010 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1011 NULL, 0);
1013 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1014 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1016 if (!d.dptr || d.dsize != 4) {
1017 SAFE_FREE(d.dptr);
1018 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1019 } else {
1020 SAFE_FREE(d.dptr);
1021 break;
1025 tdb_close(tdb);
1026 return ret;
1029 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1030 struct messaging_context *msg_ctx,
1031 const struct server_id pid,
1032 const int argc, const char **argv)
1034 struct server_id myid;
1036 myid = messaging_server_id(msg_ctx);
1038 if (argc != 1) {
1039 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1040 return False;
1043 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1044 print_pid_string_cb);
1046 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1047 sizeof(myid)))
1048 return False;
1050 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1052 /* No replies were received within the timeout period */
1054 if (num_replies == 0)
1055 printf("No replies received\n");
1057 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1059 return num_replies;
1062 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1063 struct messaging_context *msg_ctx,
1064 const struct server_id pid,
1065 const int argc, const char **argv)
1067 if (argc != 1) {
1068 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1069 return False;
1072 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1075 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1076 struct messaging_context *msg_ctx,
1077 const struct server_id pid,
1078 const int argc, const char **argv)
1080 const char *domain = NULL;
1081 int domain_len = 0;
1082 struct server_id myid;
1083 uint8_t *buf = NULL;
1084 int buf_len = 0;
1086 myid = messaging_server_id(msg_ctx);
1088 if (argc < 1 || argc > 2) {
1089 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1090 "<domain>\n");
1091 return false;
1094 if (argc == 2) {
1095 domain = argv[1];
1096 domain_len = strlen(argv[1]) + 1;
1099 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1100 print_pid_string_cb);
1102 buf_len = sizeof(myid)+domain_len;
1103 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1104 if (!buf) {
1105 return false;
1108 memcpy(buf, &myid, sizeof(myid));
1109 memcpy(&buf[sizeof(myid)], domain, domain_len);
1111 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1112 buf, buf_len))
1114 SAFE_FREE(buf);
1115 return false;
1118 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1120 /* No replies were received within the timeout period */
1122 SAFE_FREE(buf);
1123 if (num_replies == 0) {
1124 printf("No replies received\n");
1127 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1129 return num_replies;
1132 static void winbind_validate_cache_cb(struct messaging_context *msg,
1133 void *private_data,
1134 uint32_t msg_type,
1135 struct server_id pid,
1136 DATA_BLOB *data)
1138 char *src_string = server_id_str(NULL, &pid);
1139 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1140 (*(data->data) == 0 ? "" : "NOT "), src_string);
1141 TALLOC_FREE(src_string);
1142 num_replies++;
1145 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1146 struct messaging_context *msg_ctx,
1147 const struct server_id pid,
1148 const int argc, const char **argv)
1150 struct server_id myid;
1152 myid = messaging_server_id(msg_ctx);
1154 if (argc != 1) {
1155 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1156 return False;
1159 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1160 winbind_validate_cache_cb);
1162 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1163 sizeof(myid))) {
1164 return False;
1167 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1169 if (num_replies == 0) {
1170 printf("No replies received\n");
1173 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1175 return num_replies;
1178 static bool do_reload_config(struct tevent_context *ev_ctx,
1179 struct messaging_context *msg_ctx,
1180 const struct server_id pid,
1181 const int argc, const char **argv)
1183 if (argc != 1) {
1184 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1185 return False;
1188 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1191 static bool do_reload_printers(struct tevent_context *ev_ctx,
1192 struct messaging_context *msg_ctx,
1193 const struct server_id pid,
1194 const int argc, const char **argv)
1196 if (argc != 1) {
1197 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1198 return False;
1201 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1204 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1206 fstring unix_name;
1207 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1208 fstrcpy(unix_name, name);
1209 (void)strupper_m(unix_name);
1210 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1211 n->name_type = (unsigned int)type & 0xFF;
1212 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1215 static bool do_nodestatus(struct tevent_context *ev_ctx,
1216 struct messaging_context *msg_ctx,
1217 const struct server_id pid,
1218 const int argc, const char **argv)
1220 struct packet_struct p;
1222 if (argc != 2) {
1223 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1224 return False;
1227 ZERO_STRUCT(p);
1229 p.ip = interpret_addr2(argv[1]);
1230 p.port = 137;
1231 p.packet_type = NMB_PACKET;
1233 p.packet.nmb.header.name_trn_id = 10;
1234 p.packet.nmb.header.opcode = 0;
1235 p.packet.nmb.header.response = False;
1236 p.packet.nmb.header.nm_flags.bcast = False;
1237 p.packet.nmb.header.nm_flags.recursion_available = False;
1238 p.packet.nmb.header.nm_flags.recursion_desired = False;
1239 p.packet.nmb.header.nm_flags.trunc = False;
1240 p.packet.nmb.header.nm_flags.authoritative = False;
1241 p.packet.nmb.header.rcode = 0;
1242 p.packet.nmb.header.qdcount = 1;
1243 p.packet.nmb.header.ancount = 0;
1244 p.packet.nmb.header.nscount = 0;
1245 p.packet.nmb.header.arcount = 0;
1246 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1247 p.packet.nmb.question.question_type = 0x21;
1248 p.packet.nmb.question.question_class = 0x1;
1250 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1253 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1254 struct messaging_context *msg_ctx,
1255 const struct server_id pid,
1256 const int argc, const char **argv)
1258 if (argc != 1) {
1259 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1260 return false;
1262 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1265 /* A list of message type supported */
1267 static const struct {
1268 const char *name; /* Option name */
1269 bool (*fn)(struct tevent_context *ev_ctx,
1270 struct messaging_context *msg_ctx,
1271 const struct server_id pid,
1272 const int argc, const char **argv);
1273 const char *help; /* Short help text */
1274 } msg_types[] = {
1275 { "debug", do_debug, "Set debuglevel" },
1276 { "idmap", do_idmap, "Manipulate idmap cache" },
1277 { "force-election", do_election,
1278 "Force a browse election" },
1279 { "ping", do_ping, "Elicit a response" },
1280 { "profile", do_profile, "" },
1281 { "inject", do_inject_fault,
1282 "Inject a fatal signal into a running smbd"},
1283 { "stacktrace", do_daemon_stack_trace,
1284 "Display a stack trace of a daemon" },
1285 { "profilelevel", do_profilelevel, "" },
1286 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1287 { "printnotify", do_printnotify, "Send a print notify message" },
1288 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1289 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1290 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1291 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1292 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1293 { "dmalloc-mark", do_dmalloc_mark, "" },
1294 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1295 { "shutdown", do_shutdown, "Shut down daemon" },
1296 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1297 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1298 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1299 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1300 { "online", do_winbind_online, "Ask winbind to go into online state"},
1301 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1302 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1303 { "dump-event-list", do_dump_event_list, "Dump event list"},
1304 { "validate-cache" , do_winbind_validate_cache,
1305 "Validate winbind's credential cache" },
1306 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1307 { "notify-cleanup", do_notify_cleanup },
1308 { "noop", do_noop, "Do nothing" },
1309 { NULL }
1312 /* Display usage information */
1314 static void usage(poptContext pc)
1316 int i;
1318 poptPrintHelp(pc, stderr, 0);
1320 fprintf(stderr, "\n");
1321 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1322 "process ID\n");
1324 fprintf(stderr, "\n");
1325 fprintf(stderr, "<message-type> is one of:\n");
1327 for (i = 0; msg_types[i].name; i++)
1328 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1329 msg_types[i].help);
1331 fprintf(stderr, "\n");
1333 exit(1);
1336 /* Return the pid number for a string destination */
1338 static struct server_id parse_dest(struct messaging_context *msg,
1339 const char *dest)
1341 struct server_id result = {-1};
1342 pid_t pid;
1344 /* Zero is a special return value for broadcast to all processes */
1346 if (strequal(dest, "all")) {
1347 return interpret_pid(MSG_BROADCAST_PID_STR);
1350 /* Try self - useful for testing */
1352 if (strequal(dest, "self")) {
1353 return messaging_server_id(msg);
1356 /* Fix winbind typo. */
1357 if (strequal(dest, "winbind")) {
1358 dest = "winbindd";
1361 /* Check for numeric pid number */
1362 result = interpret_pid(dest);
1364 /* Zero isn't valid if not "all". */
1365 if (result.pid && procid_valid(&result)) {
1366 return result;
1369 /* Look up other destinations in pidfile directory */
1371 if ((pid = pidfile_pid(lp_piddir(), dest)) != 0) {
1372 return pid_to_procid(pid);
1375 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1377 return result;
1380 /* Execute smbcontrol command */
1382 static bool do_command(struct tevent_context *ev_ctx,
1383 struct messaging_context *msg_ctx,
1384 int argc, const char **argv)
1386 const char *dest = argv[0], *command = argv[1];
1387 struct server_id pid;
1388 int i;
1390 /* Check destination */
1392 pid = parse_dest(msg_ctx, dest);
1393 if (!procid_valid(&pid)) {
1394 return False;
1397 /* Check command */
1399 for (i = 0; msg_types[i].name; i++) {
1400 if (strequal(command, msg_types[i].name))
1401 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1402 argc - 1, argv + 1);
1405 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1407 return False;
1410 static void smbcontrol_help(poptContext pc,
1411 enum poptCallbackReason preason,
1412 struct poptOption * poption,
1413 const char * parg,
1414 void * pdata)
1416 if (poption->shortName != '?') {
1417 poptPrintUsage(pc, stdout, 0);
1418 } else {
1419 usage(pc);
1422 exit(0);
1425 struct poptOption help_options[] = {
1426 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1427 NULL, NULL },
1428 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1429 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1430 { NULL }
1433 /* Main program */
1435 int main(int argc, const char **argv)
1437 poptContext pc;
1438 int opt;
1439 struct tevent_context *evt_ctx;
1440 struct messaging_context *msg_ctx;
1442 static struct poptOption long_options[] = {
1443 /* POPT_AUTOHELP */
1444 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1445 0, "Help options:", NULL },
1446 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1447 "Set timeout value in seconds", "TIMEOUT" },
1449 POPT_COMMON_SAMBA
1450 POPT_TABLEEND
1452 TALLOC_CTX *frame = talloc_stackframe();
1453 int ret = 0;
1455 load_case_tables();
1457 setup_logging(argv[0], DEBUG_STDOUT);
1459 /* Parse command line arguments using popt */
1461 pc = poptGetContext(
1462 "smbcontrol", argc, (const char **)argv, long_options, 0);
1464 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1465 "<parameters>");
1467 if (argc == 1)
1468 usage(pc);
1470 while ((opt = poptGetNextOpt(pc)) != -1) {
1471 switch(opt) {
1472 case 't': /* --timeout */
1473 break;
1474 default:
1475 fprintf(stderr, "Invalid option\n");
1476 poptPrintHelp(pc, stderr, 0);
1477 break;
1481 /* We should now have the remaining command line arguments in
1482 argv. The argc parameter should have been decremented to the
1483 correct value in the above switch statement. */
1485 argv = (const char **)poptGetArgs(pc);
1486 argc = 0;
1487 if (argv != NULL) {
1488 while (argv[argc] != NULL) {
1489 argc++;
1493 if (argc <= 1)
1494 usage(pc);
1496 lp_load_global(get_dyn_CONFIGFILE());
1498 /* Need to invert sense of return code -- samba
1499 * routines mostly return True==1 for success, but
1500 * shell needs 0. */
1502 if (!(evt_ctx = tevent_context_init(NULL)) ||
1503 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1504 fprintf(stderr, "could not init messaging context\n");
1505 TALLOC_FREE(frame);
1506 exit(1);
1509 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1510 TALLOC_FREE(frame);
1511 return ret;