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/>.
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"
35 #include "../lib/util/pidfile.h"
39 #include <libunwind.h>
42 #if HAVE_LIBUNWIND_PTRACE_H
43 #include <libunwind-ptrace.h>
47 #include <sys/ptrace.h>
50 /* Default timeout value when waiting for replies (in seconds) */
52 #define DEFAULT_TIMEOUT 10
54 static int timeout
= DEFAULT_TIMEOUT
;
55 static int num_replies
; /* Used by message callback fns */
57 /* Send a message to a destination pid. Zero means broadcast smbd. */
59 static bool send_message(struct messaging_context
*msg_ctx
,
60 struct server_id pid
, int msg_type
,
61 const void *buf
, int len
)
66 if (procid_to_pid(&pid
) != 0)
67 return NT_STATUS_IS_OK(
68 messaging_send_buf(msg_ctx
, pid
, msg_type
,
69 (const uint8
*)buf
, len
));
71 ret
= message_send_all(msg_ctx
, msg_type
, buf
, len
, &n_sent
);
72 DEBUG(10,("smbcontrol/send_message: broadcast message to "
73 "%d processes\n", n_sent
));
78 static void smbcontrol_timeout(struct tevent_context
*event_ctx
,
79 struct tevent_timer
*te
,
83 bool *timed_out
= (bool *)private_data
;
88 /* Wait for one or more reply messages */
90 static void wait_replies(struct tevent_context
*ev_ctx
,
91 struct messaging_context
*msg_ctx
,
92 bool multiple_replies
)
94 struct tevent_timer
*te
;
95 bool timed_out
= False
;
97 te
= tevent_add_timer(ev_ctx
, NULL
,
98 timeval_current_ofs(timeout
, 0),
99 smbcontrol_timeout
, (void *)&timed_out
);
101 DEBUG(0, ("tevent_add_timer failed\n"));
107 if (num_replies
> 0 && !multiple_replies
)
109 ret
= tevent_loop_once(ev_ctx
);
116 /* Message handler callback that displays the PID and a string on stdout */
118 static void print_pid_string_cb(struct messaging_context
*msg
,
121 struct server_id pid
,
126 pidstr
= server_id_str(talloc_tos(), &pid
);
127 printf("PID %s: %.*s", pidstr
, (int)data
->length
,
128 (const char *)data
->data
);
133 /* Message handler callback that displays a string on stdout */
135 static void print_string_cb(struct messaging_context
*msg
,
138 struct server_id pid
,
141 printf("%*s", (int)data
->length
, (const char *)data
->data
);
145 /* Send no message. Useful for testing. */
147 static bool do_noop(struct tevent_context
*ev_ctx
,
148 struct messaging_context
*msg_ctx
,
149 const struct server_id pid
,
150 const int argc
, const char **argv
)
153 fprintf(stderr
, "Usage: smbcontrol <dest> noop\n");
157 /* Move along, nothing to see here */
162 /* Send a debug string */
164 static bool do_debug(struct tevent_context
*ev_ctx
,
165 struct messaging_context
*msg_ctx
,
166 const struct server_id pid
,
167 const int argc
, const char **argv
)
170 fprintf(stderr
, "Usage: smbcontrol <dest> debug "
175 return send_message(msg_ctx
, pid
, MSG_DEBUG
, argv
[1],
176 strlen(argv
[1]) + 1);
180 static bool do_idmap(struct tevent_context
*ev
,
181 struct messaging_context
*msg_ctx
,
182 const struct server_id pid
,
183 const int argc
, const char **argv
)
185 static const char* usage
= "Usage: "
186 "smbcontrol <dest> idmap <cmd> [arg]\n"
188 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
189 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
190 const char* arg
= NULL
;
199 arglen
= strlen(arg
) + 1;
202 fprintf(stderr
, "%s", usage
);
206 if (strcmp(argv
[1], "delete") == 0) {
207 msg_type
= ID_CACHE_DELETE
;
209 else if (strcmp(argv
[1], "kill") == 0) {
210 msg_type
= ID_CACHE_KILL
;
212 else if (strcmp(argv
[1], "help") == 0) {
213 fprintf(stdout
, "%s", usage
);
217 fprintf(stderr
, "%s", usage
);
221 return send_message(msg_ctx
, pid
, msg_type
, arg
, arglen
);
225 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
227 /* Return the name of a process given it's PID. This will only work on Linux,
228 * but that's probably moot since this whole stack tracing implementatino is
229 * Linux-specific anyway.
231 static const char * procname(pid_t pid
, char * buf
, size_t bufsz
)
236 snprintf(path
, sizeof(path
), "/proc/%llu/cmdline",
237 (unsigned long long)pid
);
238 if ((fp
= fopen(path
, "r")) == NULL
) {
242 fgets(buf
, bufsz
, fp
);
248 static void print_stack_trace(pid_t pid
, int * count
)
251 unw_addr_space_t aspace
= NULL
;
260 if (ptrace(PTRACE_ATTACH
, pid
, NULL
, NULL
) < 0) {
262 "Failed to attach to process %llu: %s\n",
263 (unsigned long long)pid
, strerror(errno
));
267 /* Wait until the attach is complete. */
268 waitpid(pid
, NULL
, 0);
270 if (((pinfo
= _UPT_create(pid
)) == NULL
) ||
271 ((aspace
= unw_create_addr_space(&_UPT_accessors
, 0)) == NULL
)) {
272 /* Probably out of memory. */
274 "Unable to initialize stack unwind for process %llu\n",
275 (unsigned long long)pid
);
279 if ((ret
= unw_init_remote(&cursor
, aspace
, pinfo
))) {
281 "Unable to unwind stack for process %llu: %s\n",
282 (unsigned long long)pid
, unw_strerror(ret
));
290 if (procname(pid
, nbuf
, sizeof(nbuf
))) {
291 printf("Stack trace for process %llu (%s):\n",
292 (unsigned long long)pid
, nbuf
);
294 printf("Stack trace for process %llu:\n",
295 (unsigned long long)pid
);
298 while (unw_step(&cursor
) > 0) {
300 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
301 unw_get_reg(&cursor
, UNW_REG_SP
, &sp
);
303 ret
= unw_get_proc_name(&cursor
, nbuf
, sizeof(nbuf
), &off
);
304 if (ret
!= 0 && ret
!= -UNW_ENOMEM
) {
305 snprintf(nbuf
, sizeof(nbuf
), "<unknown symbol>");
307 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
308 nbuf
, (long long)off
, (long long)ip
,
316 unw_destroy_addr_space(aspace
);
323 ptrace(PTRACE_DETACH
, pid
, NULL
, NULL
);
326 static int stack_trace_server(const struct server_id
*id
,
330 if (id
->vnn
== get_my_vnn()) {
331 print_stack_trace(procid_to_pid(id
), (int *)priv
);
336 static bool do_daemon_stack_trace(struct tevent_context
*ev_ctx
,
337 struct messaging_context
*msg_ctx
,
338 const struct server_id pid
,
339 const int argc
, const char **argv
)
345 fprintf(stderr
, "Usage: smbcontrol <dest> stacktrace\n");
349 dest
= procid_to_pid(&pid
);
352 /* It would be nice to be able to make sure that this PID is
353 * the PID of a smbd/winbind/nmbd process, not some random PID
354 * the user liked the look of. It doesn't seem like it's worth
355 * the effort at the moment, however.
357 print_stack_trace(dest
, &count
);
359 serverid_traverse_read(stack_trace_server
, &count
);
365 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
367 static bool do_daemon_stack_trace(struct tevent_context
*ev_ctx
,
368 struct messaging_context
*msg_ctx
,
369 const struct server_id pid
,
370 const int argc
, const char **argv
)
373 "Daemon stack tracing is not supported on this platform\n");
377 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
379 /* Inject a fault (fatal signal) into a running smbd */
381 static bool do_inject_fault(struct tevent_context
*ev_ctx
,
382 struct messaging_context
*msg_ctx
,
383 const struct server_id pid
,
384 const int argc
, const char **argv
)
387 fprintf(stderr
, "Usage: smbcontrol <dest> inject "
388 "<bus|hup|term|internal|segv>\n");
393 fprintf(stderr
, "Fault injection is only available in "
394 "developer builds\n");
396 #else /* DEVELOPER */
400 if (strcmp(argv
[1], "bus") == 0) {
402 } else if (strcmp(argv
[1], "hup") == 0) {
404 } else if (strcmp(argv
[1], "term") == 0) {
406 } else if (strcmp(argv
[1], "segv") == 0) {
408 } else if (strcmp(argv
[1], "internal") == 0) {
409 /* Force an internal error, ie. an unclean exit. */
412 fprintf(stderr
, "Unknown signal name '%s'\n", argv
[1]);
416 return send_message(msg_ctx
, pid
, MSG_SMB_INJECT_FAULT
,
419 #endif /* DEVELOPER */
422 /* Force a browser election */
424 static bool do_election(struct tevent_context
*ev_ctx
,
425 struct messaging_context
*msg_ctx
,
426 const struct server_id pid
,
427 const int argc
, const char **argv
)
430 fprintf(stderr
, "Usage: smbcontrol <dest> force-election\n");
434 return send_message(msg_ctx
, pid
, MSG_FORCE_ELECTION
, NULL
, 0);
437 /* Ping a samba daemon process */
439 static void pong_cb(struct messaging_context
*msg
,
442 struct server_id pid
,
445 char *src_string
= server_id_str(NULL
, &pid
);
446 printf("PONG from pid %s\n", src_string
);
447 TALLOC_FREE(src_string
);
451 static bool do_ping(struct tevent_context
*ev_ctx
,
452 struct messaging_context
*msg_ctx
,
453 const struct server_id pid
,
454 const int argc
, const char **argv
)
457 fprintf(stderr
, "Usage: smbcontrol <dest> ping\n");
461 /* Send a message and register our interest in a reply */
463 if (!send_message(msg_ctx
, pid
, MSG_PING
, NULL
, 0))
466 messaging_register(msg_ctx
, NULL
, MSG_PONG
, pong_cb
);
468 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
470 /* No replies were received within the timeout period */
472 if (num_replies
== 0)
473 printf("No replies received\n");
475 messaging_deregister(msg_ctx
, MSG_PONG
, NULL
);
480 /* Set profiling options */
482 static bool do_profile(struct tevent_context
*ev_ctx
,
483 struct messaging_context
*msg_ctx
,
484 const struct server_id pid
,
485 const int argc
, const char **argv
)
490 fprintf(stderr
, "Usage: smbcontrol <dest> profile "
491 "<off|count|on|flush>\n");
495 if (strcmp(argv
[1], "off") == 0) {
497 } else if (strcmp(argv
[1], "count") == 0) {
499 } else if (strcmp(argv
[1], "on") == 0) {
501 } else if (strcmp(argv
[1], "flush") == 0) {
504 fprintf(stderr
, "Unknown profile command '%s'\n", argv
[1]);
508 return send_message(msg_ctx
, pid
, MSG_PROFILE
, &v
, sizeof(int));
511 /* Return the profiling level */
513 static void profilelevel_cb(struct messaging_context
*msg_ctx
,
516 struct server_id pid
,
524 if (data
->length
!= sizeof(int)) {
525 fprintf(stderr
, "invalid message length %ld returned\n",
526 (unsigned long)data
->length
);
530 memcpy(&level
, data
->data
, sizeof(int));
543 s
= "count and time";
550 printf("Profiling %s on pid %u\n",s
,(unsigned int)procid_to_pid(&pid
));
553 static void profilelevel_rqst(struct messaging_context
*msg_ctx
,
556 struct server_id pid
,
561 /* Send back a dummy reply */
563 send_message(msg_ctx
, pid
, MSG_PROFILELEVEL
, &v
, sizeof(int));
566 static bool do_profilelevel(struct tevent_context
*ev_ctx
,
567 struct messaging_context
*msg_ctx
,
568 const struct server_id pid
,
569 const int argc
, const char **argv
)
572 fprintf(stderr
, "Usage: smbcontrol <dest> profilelevel\n");
576 /* Send a message and register our interest in a reply */
578 if (!send_message(msg_ctx
, pid
, MSG_REQ_PROFILELEVEL
, NULL
, 0))
581 messaging_register(msg_ctx
, NULL
, MSG_PROFILELEVEL
, profilelevel_cb
);
582 messaging_register(msg_ctx
, NULL
, MSG_REQ_PROFILELEVEL
,
585 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
587 /* No replies were received within the timeout period */
589 if (num_replies
== 0)
590 printf("No replies received\n");
592 messaging_deregister(msg_ctx
, MSG_PROFILE
, NULL
);
597 /* Display debug level settings */
599 static bool do_debuglevel(struct tevent_context
*ev_ctx
,
600 struct messaging_context
*msg_ctx
,
601 const struct server_id pid
,
602 const int argc
, const char **argv
)
605 fprintf(stderr
, "Usage: smbcontrol <dest> debuglevel\n");
609 /* Send a message and register our interest in a reply */
611 if (!send_message(msg_ctx
, pid
, MSG_REQ_DEBUGLEVEL
, NULL
, 0))
614 messaging_register(msg_ctx
, NULL
, MSG_DEBUGLEVEL
, print_pid_string_cb
);
616 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
618 /* No replies were received within the timeout period */
620 if (num_replies
== 0)
621 printf("No replies received\n");
623 messaging_deregister(msg_ctx
, MSG_DEBUGLEVEL
, NULL
);
628 /* Send a print notify message */
630 static bool do_printnotify(struct tevent_context
*ev_ctx
,
631 struct messaging_context
*msg_ctx
,
632 const struct server_id pid
,
633 const int argc
, const char **argv
)
637 /* Check for subcommand */
640 fprintf(stderr
, "Must specify subcommand:\n");
641 fprintf(stderr
, "\tqueuepause <printername>\n");
642 fprintf(stderr
, "\tqueueresume <printername>\n");
643 fprintf(stderr
, "\tjobpause <printername> <unix jobid>\n");
644 fprintf(stderr
, "\tjobresume <printername> <unix jobid>\n");
645 fprintf(stderr
, "\tjobdelete <printername> <unix jobid>\n");
646 fprintf(stderr
, "\tprinter <printername> <comment|port|"
647 "driver> <value>\n");
654 if (strcmp(cmd
, "queuepause") == 0) {
657 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
658 " queuepause <printername>\n");
662 notify_printer_status_byname(ev_ctx
, msg_ctx
, argv
[2],
663 PRINTER_STATUS_PAUSED
);
667 } else if (strcmp(cmd
, "queueresume") == 0) {
670 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
671 " queuereume <printername>\n");
675 notify_printer_status_byname(ev_ctx
, msg_ctx
, argv
[2],
680 } else if (strcmp(cmd
, "jobpause") == 0) {
684 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
685 " jobpause <printername> <unix-jobid>\n");
689 jobid
= atoi(argv
[3]);
691 notify_job_status_byname(
693 argv
[2], jobid
, JOB_STATUS_PAUSED
,
694 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
698 } else if (strcmp(cmd
, "jobresume") == 0) {
702 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
703 " jobpause <printername> <unix-jobid>\n");
707 jobid
= atoi(argv
[3]);
709 notify_job_status_byname(
711 argv
[2], jobid
, JOB_STATUS_QUEUED
,
712 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
716 } else if (strcmp(cmd
, "jobdelete") == 0) {
720 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
721 " jobpause <printername> <unix-jobid>\n");
725 jobid
= atoi(argv
[3]);
727 notify_job_status_byname(
729 argv
[2], jobid
, JOB_STATUS_DELETING
,
730 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
732 notify_job_status_byname(
734 argv
[2], jobid
, JOB_STATUS_DELETING
|
736 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
740 } else if (strcmp(cmd
, "printer") == 0) {
744 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify "
745 "printer <printername> <comment|port|driver> "
750 if (strcmp(argv
[3], "comment") == 0) {
751 attribute
= PRINTER_NOTIFY_FIELD_COMMENT
;
752 } else if (strcmp(argv
[3], "port") == 0) {
753 attribute
= PRINTER_NOTIFY_FIELD_PORT_NAME
;
754 } else if (strcmp(argv
[3], "driver") == 0) {
755 attribute
= PRINTER_NOTIFY_FIELD_DRIVER_NAME
;
757 fprintf(stderr
, "Invalid printer command '%s'\n",
762 notify_printer_byname(ev_ctx
, msg_ctx
, argv
[2], attribute
,
763 discard_const_p(char, argv
[4]));
768 fprintf(stderr
, "Invalid subcommand '%s'\n", cmd
);
772 print_notify_send_messages(msg_ctx
, 0);
778 static bool do_closeshare(struct tevent_context
*ev_ctx
,
779 struct messaging_context
*msg_ctx
,
780 const struct server_id pid
,
781 const int argc
, const char **argv
)
784 fprintf(stderr
, "Usage: smbcontrol <dest> close-share "
789 return send_message(msg_ctx
, pid
, MSG_SMB_FORCE_TDIS
, argv
[1],
790 strlen(argv
[1]) + 1);
793 /* Kill a client by IP address */
794 static bool do_kill_client_by_ip(struct tevent_context
*ev_ctx
,
795 struct messaging_context
*msg_ctx
,
796 const struct server_id pid
,
797 const int argc
, const char **argv
)
800 fprintf(stderr
, "Usage: smbcontrol <dest> kill-client-ip "
805 if (!is_ipaddress_v4(argv
[1]) && !is_ipaddress_v6(argv
[1])) {
806 fprintf(stderr
, "%s is not a valid IP address!\n", argv
[1]);
810 return send_message(msg_ctx
, pid
, MSG_SMB_KILL_CLIENT_IP
,
811 argv
[1], strlen(argv
[1]) + 1);
814 /* Tell winbindd an IP got dropped */
816 static bool do_ip_dropped(struct tevent_context
*ev_ctx
,
817 struct messaging_context
*msg_ctx
,
818 const struct server_id pid
,
819 const int argc
, const char **argv
)
822 fprintf(stderr
, "Usage: smbcontrol <dest> ip-dropped "
827 return send_message(msg_ctx
, pid
, MSG_WINBIND_IP_DROPPED
, argv
[1],
828 strlen(argv
[1]) + 1);
831 /* force a blocking lock retry */
833 static bool do_lockretry(struct tevent_context
*ev_ctx
,
834 struct messaging_context
*msg_ctx
,
835 const struct server_id pid
,
836 const int argc
, const char **argv
)
839 fprintf(stderr
, "Usage: smbcontrol <dest> lockretry\n");
843 return send_message(msg_ctx
, pid
, MSG_SMB_UNLOCK
, NULL
, 0);
846 /* force a validation of all brl entries, including re-sends. */
848 static bool do_brl_revalidate(struct tevent_context
*ev_ctx
,
849 struct messaging_context
*msg_ctx
,
850 const struct server_id pid
,
851 const int argc
, const char **argv
)
854 fprintf(stderr
, "Usage: smbcontrol <dest> brl-revalidate\n");
858 return send_message(msg_ctx
, pid
, MSG_SMB_BRL_VALIDATE
, NULL
, 0);
861 /* Display talloc pool usage */
863 static bool do_poolusage(struct tevent_context
*ev_ctx
,
864 struct messaging_context
*msg_ctx
,
865 const struct server_id pid
,
866 const int argc
, const char **argv
)
869 fprintf(stderr
, "Usage: smbcontrol <dest> pool-usage\n");
873 messaging_register(msg_ctx
, NULL
, MSG_POOL_USAGE
, print_string_cb
);
875 /* Send a message and register our interest in a reply */
877 if (!send_message(msg_ctx
, pid
, MSG_REQ_POOL_USAGE
, NULL
, 0))
880 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
882 /* No replies were received within the timeout period */
884 if (num_replies
== 0)
885 printf("No replies received\n");
887 messaging_deregister(msg_ctx
, MSG_POOL_USAGE
, NULL
);
892 /* Perform a dmalloc mark */
894 static bool do_dmalloc_mark(struct tevent_context
*ev_ctx
,
895 struct messaging_context
*msg_ctx
,
896 const struct server_id pid
,
897 const int argc
, const char **argv
)
900 fprintf(stderr
, "Usage: smbcontrol <dest> dmalloc-mark\n");
904 return send_message(msg_ctx
, pid
, MSG_REQ_DMALLOC_MARK
, NULL
, 0);
907 /* Perform a dmalloc changed */
909 static bool do_dmalloc_changed(struct tevent_context
*ev_ctx
,
910 struct messaging_context
*msg_ctx
,
911 const struct server_id pid
,
912 const int argc
, const char **argv
)
915 fprintf(stderr
, "Usage: smbcontrol <dest> "
916 "dmalloc-log-changed\n");
920 return send_message(msg_ctx
, pid
, MSG_REQ_DMALLOC_LOG_CHANGED
,
924 static void print_uint32_cb(struct messaging_context
*msg
, void *private_data
,
925 uint32_t msg_type
, struct server_id pid
,
928 uint32_t num_children
;
930 if (data
->length
!= sizeof(uint32_t)) {
931 printf("Invalid response: %d bytes long\n",
935 num_children
= IVAL(data
->data
, 0);
936 printf("%u children\n", (unsigned)num_children
);
941 static bool do_num_children(struct tevent_context
*ev_ctx
,
942 struct messaging_context
*msg_ctx
,
943 const struct server_id pid
,
944 const int argc
, const char **argv
)
947 fprintf(stderr
, "Usage: smbcontrol <dest> num-children\n");
951 messaging_register(msg_ctx
, NULL
, MSG_SMB_NUM_CHILDREN
,
954 /* Send a message and register our interest in a reply */
956 if (!send_message(msg_ctx
, pid
, MSG_SMB_TELL_NUM_CHILDREN
, NULL
, 0))
959 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
961 /* No replies were received within the timeout period */
963 if (num_replies
== 0)
964 printf("No replies received\n");
966 messaging_deregister(msg_ctx
, MSG_SMB_NUM_CHILDREN
, NULL
);
971 static bool do_dgm_cleanup(struct tevent_context
*ev_ctx
,
972 struct messaging_context
*msg_ctx
,
973 const struct server_id pid
,
974 const int argc
, const char **argv
)
979 ret
= messaging_dgm_cleanup(msg_ctx
, pid
.pid
);
981 ret
= messaging_dgm_wipe(msg_ctx
);
984 printf("cleanup(%u) returned %s\n", (unsigned)pid
.pid
,
985 ret
? strerror(ret
) : "ok");
990 /* Shutdown a server process */
992 static bool do_shutdown(struct tevent_context
*ev_ctx
,
993 struct messaging_context
*msg_ctx
,
994 const struct server_id pid
,
995 const int argc
, const char **argv
)
998 fprintf(stderr
, "Usage: smbcontrol <dest> shutdown\n");
1002 return send_message(msg_ctx
, pid
, MSG_SHUTDOWN
, NULL
, 0);
1005 /* Notify a driver upgrade */
1007 static bool do_drvupgrade(struct tevent_context
*ev_ctx
,
1008 struct messaging_context
*msg_ctx
,
1009 const struct server_id pid
,
1010 const int argc
, const char **argv
)
1013 fprintf(stderr
, "Usage: smbcontrol <dest> drvupgrade "
1018 return send_message(msg_ctx
, pid
, MSG_PRINTER_DRVUPGRADE
, argv
[1],
1019 strlen(argv
[1]) + 1);
1022 static bool do_winbind_online(struct tevent_context
*ev_ctx
,
1023 struct messaging_context
*msg_ctx
,
1024 const struct server_id pid
,
1025 const int argc
, const char **argv
)
1030 fprintf(stderr
, "Usage: smbcontrol winbindd online\n");
1034 /* Remove the entry in the winbindd_cache tdb to tell a later
1035 starting winbindd that we're online. */
1037 tdb
= tdb_open_log(state_path("winbindd_cache.tdb"), 0, TDB_DEFAULT
, O_RDWR
, 0600);
1039 fprintf(stderr
, "Cannot open the tdb %s for writing.\n",
1040 state_path("winbindd_cache.tdb"));
1044 tdb_delete_bystring(tdb
, "WINBINDD_OFFLINE");
1047 return send_message(msg_ctx
, pid
, MSG_WINBIND_ONLINE
, NULL
, 0);
1050 static bool do_winbind_offline(struct tevent_context
*ev_ctx
,
1051 struct messaging_context
*msg_ctx
,
1052 const struct server_id pid
,
1053 const int argc
, const char **argv
)
1060 fprintf(stderr
, "Usage: smbcontrol winbindd offline\n");
1064 /* Create an entry in the winbindd_cache tdb to tell a later
1065 starting winbindd that we're offline. We may actually create
1068 tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
1069 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
1070 TDB_DEFAULT
|TDB_INCOMPATIBLE_HASH
/* TDB_CLEAR_IF_FIRST */,
1071 O_RDWR
|O_CREAT
, 0600);
1074 fprintf(stderr
, "Cannot open the tdb %s for writing.\n",
1075 state_path("winbindd_cache.tdb"));
1079 /* There's a potential race condition that if a child
1080 winbindd detects a domain is online at the same time
1081 we're trying to tell it to go offline that it might
1082 delete the record we add between us adding it and
1083 sending the message. Minimize this by retrying up to
1086 for (retry
= 0; retry
< 5; retry
++) {
1092 SIVAL(buf
, 0, time(NULL
));
1096 tdb_store_bystring(tdb
, "WINBINDD_OFFLINE", d
, TDB_INSERT
);
1098 ret
= send_message(msg_ctx
, pid
, MSG_WINBIND_OFFLINE
,
1101 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1102 d
= tdb_fetch_bystring( tdb
, "WINBINDD_OFFLINE" );
1104 if (!d
.dptr
|| d
.dsize
!= 4) {
1106 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1117 static bool do_winbind_onlinestatus(struct tevent_context
*ev_ctx
,
1118 struct messaging_context
*msg_ctx
,
1119 const struct server_id pid
,
1120 const int argc
, const char **argv
)
1122 struct server_id myid
;
1124 myid
= messaging_server_id(msg_ctx
);
1127 fprintf(stderr
, "Usage: smbcontrol winbindd onlinestatus\n");
1131 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_ONLINESTATUS
,
1132 print_pid_string_cb
);
1134 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_ONLINESTATUS
, &myid
,
1138 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1140 /* No replies were received within the timeout period */
1142 if (num_replies
== 0)
1143 printf("No replies received\n");
1145 messaging_deregister(msg_ctx
, MSG_WINBIND_ONLINESTATUS
, NULL
);
1150 static bool do_dump_event_list(struct tevent_context
*ev_ctx
,
1151 struct messaging_context
*msg_ctx
,
1152 const struct server_id pid
,
1153 const int argc
, const char **argv
)
1156 fprintf(stderr
, "Usage: smbcontrol <dest> dump-event-list\n");
1160 return send_message(msg_ctx
, pid
, MSG_DUMP_EVENT_LIST
, NULL
, 0);
1163 static bool do_winbind_dump_domain_list(struct tevent_context
*ev_ctx
,
1164 struct messaging_context
*msg_ctx
,
1165 const struct server_id pid
,
1166 const int argc
, const char **argv
)
1168 const char *domain
= NULL
;
1170 struct server_id myid
;
1171 uint8_t *buf
= NULL
;
1174 myid
= messaging_server_id(msg_ctx
);
1176 if (argc
< 1 || argc
> 2) {
1177 fprintf(stderr
, "Usage: smbcontrol <dest> dump-domain-list "
1184 domain_len
= strlen(argv
[1]) + 1;
1187 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_DUMP_DOMAIN_LIST
,
1188 print_pid_string_cb
);
1190 buf_len
= sizeof(myid
)+domain_len
;
1191 buf
= SMB_MALLOC_ARRAY(uint8_t, buf_len
);
1196 memcpy(buf
, &myid
, sizeof(myid
));
1197 memcpy(&buf
[sizeof(myid
)], domain
, domain_len
);
1199 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_DUMP_DOMAIN_LIST
,
1206 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1208 /* No replies were received within the timeout period */
1211 if (num_replies
== 0) {
1212 printf("No replies received\n");
1215 messaging_deregister(msg_ctx
, MSG_WINBIND_DUMP_DOMAIN_LIST
, NULL
);
1220 static void winbind_validate_cache_cb(struct messaging_context
*msg
,
1223 struct server_id pid
,
1226 char *src_string
= server_id_str(NULL
, &pid
);
1227 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1228 (*(data
->data
) == 0 ? "" : "NOT "), src_string
);
1229 TALLOC_FREE(src_string
);
1233 static bool do_winbind_validate_cache(struct tevent_context
*ev_ctx
,
1234 struct messaging_context
*msg_ctx
,
1235 const struct server_id pid
,
1236 const int argc
, const char **argv
)
1238 struct server_id myid
;
1240 myid
= messaging_server_id(msg_ctx
);
1243 fprintf(stderr
, "Usage: smbcontrol winbindd validate-cache\n");
1247 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_VALIDATE_CACHE
,
1248 winbind_validate_cache_cb
);
1250 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_VALIDATE_CACHE
, &myid
,
1255 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1257 if (num_replies
== 0) {
1258 printf("No replies received\n");
1261 messaging_deregister(msg_ctx
, MSG_WINBIND_VALIDATE_CACHE
, NULL
);
1266 static bool do_reload_config(struct tevent_context
*ev_ctx
,
1267 struct messaging_context
*msg_ctx
,
1268 const struct server_id pid
,
1269 const int argc
, const char **argv
)
1272 fprintf(stderr
, "Usage: smbcontrol <dest> reload-config\n");
1276 return send_message(msg_ctx
, pid
, MSG_SMB_CONF_UPDATED
, NULL
, 0);
1279 static bool do_reload_printers(struct tevent_context
*ev_ctx
,
1280 struct messaging_context
*msg_ctx
,
1281 const struct server_id pid
,
1282 const int argc
, const char **argv
)
1285 fprintf(stderr
, "Usage: smbcontrol <dest> reload-printers\n");
1289 return send_message(msg_ctx
, pid
, MSG_PRINTER_PCAP
, NULL
, 0);
1292 static void my_make_nmb_name( struct nmb_name
*n
, const char *name
, int type
)
1295 memset( (char *)n
, '\0', sizeof(struct nmb_name
) );
1296 fstrcpy(unix_name
, name
);
1297 (void)strupper_m(unix_name
);
1298 push_ascii(n
->name
, unix_name
, sizeof(n
->name
), STR_TERMINATE
);
1299 n
->name_type
= (unsigned int)type
& 0xFF;
1300 push_ascii(n
->scope
, lp_netbios_scope(), 64, STR_TERMINATE
);
1303 static bool do_nodestatus(struct tevent_context
*ev_ctx
,
1304 struct messaging_context
*msg_ctx
,
1305 const struct server_id pid
,
1306 const int argc
, const char **argv
)
1308 struct packet_struct p
;
1311 fprintf(stderr
, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1317 p
.ip
= interpret_addr2(argv
[1]);
1319 p
.packet_type
= NMB_PACKET
;
1321 p
.packet
.nmb
.header
.name_trn_id
= 10;
1322 p
.packet
.nmb
.header
.opcode
= 0;
1323 p
.packet
.nmb
.header
.response
= False
;
1324 p
.packet
.nmb
.header
.nm_flags
.bcast
= False
;
1325 p
.packet
.nmb
.header
.nm_flags
.recursion_available
= False
;
1326 p
.packet
.nmb
.header
.nm_flags
.recursion_desired
= False
;
1327 p
.packet
.nmb
.header
.nm_flags
.trunc
= False
;
1328 p
.packet
.nmb
.header
.nm_flags
.authoritative
= False
;
1329 p
.packet
.nmb
.header
.rcode
= 0;
1330 p
.packet
.nmb
.header
.qdcount
= 1;
1331 p
.packet
.nmb
.header
.ancount
= 0;
1332 p
.packet
.nmb
.header
.nscount
= 0;
1333 p
.packet
.nmb
.header
.arcount
= 0;
1334 my_make_nmb_name(&p
.packet
.nmb
.question
.question_name
, "*", 0x00);
1335 p
.packet
.nmb
.question
.question_type
= 0x21;
1336 p
.packet
.nmb
.question
.question_class
= 0x1;
1338 return send_message(msg_ctx
, pid
, MSG_SEND_PACKET
, &p
, sizeof(p
));
1341 static bool do_notify_cleanup(struct tevent_context
*ev_ctx
,
1342 struct messaging_context
*msg_ctx
,
1343 const struct server_id pid
,
1344 const int argc
, const char **argv
)
1347 fprintf(stderr
, "Usage: smbcontrol smbd notify-cleanup\n");
1350 return send_message(msg_ctx
, pid
, MSG_SMB_NOTIFY_CLEANUP
, NULL
, 0);
1353 /* A list of message type supported */
1355 static const struct {
1356 const char *name
; /* Option name */
1357 bool (*fn
)(struct tevent_context
*ev_ctx
,
1358 struct messaging_context
*msg_ctx
,
1359 const struct server_id pid
,
1360 const int argc
, const char **argv
);
1361 const char *help
; /* Short help text */
1363 { "debug", do_debug
, "Set debuglevel" },
1364 { "idmap", do_idmap
, "Manipulate idmap cache" },
1365 { "force-election", do_election
,
1366 "Force a browse election" },
1367 { "ping", do_ping
, "Elicit a response" },
1368 { "profile", do_profile
, "" },
1369 { "inject", do_inject_fault
,
1370 "Inject a fatal signal into a running smbd"},
1371 { "stacktrace", do_daemon_stack_trace
,
1372 "Display a stack trace of a daemon" },
1373 { "profilelevel", do_profilelevel
, "" },
1374 { "debuglevel", do_debuglevel
, "Display current debuglevels" },
1375 { "printnotify", do_printnotify
, "Send a print notify message" },
1376 { "close-share", do_closeshare
, "Forcibly disconnect a share" },
1377 { "kill-client-ip", do_kill_client_by_ip
,
1378 "Forcibly disconnect a client with a specific IP address" },
1379 { "ip-dropped", do_ip_dropped
, "Tell winbind that an IP got dropped" },
1380 { "lockretry", do_lockretry
, "Force a blocking lock retry" },
1381 { "brl-revalidate", do_brl_revalidate
, "Revalidate all brl entries" },
1382 { "pool-usage", do_poolusage
, "Display talloc memory usage" },
1383 { "dmalloc-mark", do_dmalloc_mark
, "" },
1384 { "dmalloc-log-changed", do_dmalloc_changed
, "" },
1385 { "shutdown", do_shutdown
, "Shut down daemon" },
1386 { "drvupgrade", do_drvupgrade
, "Notify a printer driver has changed" },
1387 { "reload-config", do_reload_config
, "Force smbd or winbindd to reload config file"},
1388 { "reload-printers", do_reload_printers
, "Force smbd to reload printers"},
1389 { "nodestatus", do_nodestatus
, "Ask nmbd to do a node status request"},
1390 { "online", do_winbind_online
, "Ask winbind to go into online state"},
1391 { "offline", do_winbind_offline
, "Ask winbind to go into offline state"},
1392 { "onlinestatus", do_winbind_onlinestatus
, "Request winbind online status"},
1393 { "dump-event-list", do_dump_event_list
, "Dump event list"},
1394 { "validate-cache" , do_winbind_validate_cache
,
1395 "Validate winbind's credential cache" },
1396 { "dump-domain-list", do_winbind_dump_domain_list
, "Dump winbind domain list"},
1397 { "notify-cleanup", do_notify_cleanup
},
1398 { "num-children", do_num_children
,
1399 "Print number of smbd child processes" },
1400 { "dgm-cleanup", do_dgm_cleanup
},
1401 { "noop", do_noop
, "Do nothing" },
1405 /* Display usage information */
1407 static void usage(poptContext pc
)
1411 poptPrintHelp(pc
, stderr
, 0);
1413 fprintf(stderr
, "\n");
1414 fprintf(stderr
, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1417 fprintf(stderr
, "\n");
1418 fprintf(stderr
, "<message-type> is one of:\n");
1420 for (i
= 0; msg_types
[i
].name
; i
++)
1421 fprintf(stderr
, "\t%-30s%s\n", msg_types
[i
].name
,
1424 fprintf(stderr
, "\n");
1429 /* Return the pid number for a string destination */
1431 static struct server_id
parse_dest(struct messaging_context
*msg
,
1434 struct server_id result
= {-1};
1437 /* Zero is a special return value for broadcast to all processes */
1439 if (strequal(dest
, "all")) {
1440 return interpret_pid(MSG_BROADCAST_PID_STR
);
1443 /* Try self - useful for testing */
1445 if (strequal(dest
, "self")) {
1446 return messaging_server_id(msg
);
1449 /* Fix winbind typo. */
1450 if (strequal(dest
, "winbind")) {
1454 /* Check for numeric pid number */
1455 result
= interpret_pid(dest
);
1457 /* Zero isn't valid if not "all". */
1458 if (result
.pid
&& procid_valid(&result
)) {
1462 /* Look up other destinations in pidfile directory */
1464 if ((pid
= pidfile_pid(lp_pid_directory(), dest
)) != 0) {
1465 return pid_to_procid(pid
);
1468 fprintf(stderr
,"Can't find pid for destination '%s'\n", dest
);
1473 /* Execute smbcontrol command */
1475 static bool do_command(struct tevent_context
*ev_ctx
,
1476 struct messaging_context
*msg_ctx
,
1477 int argc
, const char **argv
)
1479 const char *dest
= argv
[0], *command
= argv
[1];
1480 struct server_id pid
;
1483 /* Check destination */
1485 pid
= parse_dest(msg_ctx
, dest
);
1486 if (!procid_valid(&pid
)) {
1492 for (i
= 0; msg_types
[i
].name
; i
++) {
1493 if (strequal(command
, msg_types
[i
].name
))
1494 return msg_types
[i
].fn(ev_ctx
, msg_ctx
, pid
,
1495 argc
- 1, argv
+ 1);
1498 fprintf(stderr
, "smbcontrol: unknown command '%s'\n", command
);
1503 static void smbcontrol_help(poptContext pc
,
1504 enum poptCallbackReason preason
,
1505 struct poptOption
* poption
,
1509 if (poption
->shortName
!= '?') {
1510 poptPrintUsage(pc
, stdout
, 0);
1518 struct poptOption help_options
[] = {
1519 { NULL
, '\0', POPT_ARG_CALLBACK
, (void *)&smbcontrol_help
, '\0',
1521 { "help", '?', 0, NULL
, '?', "Show this help message", NULL
},
1522 { "usage", '\0', 0, NULL
, 'u', "Display brief usage message", NULL
},
1528 int main(int argc
, const char **argv
)
1532 struct tevent_context
*evt_ctx
;
1533 struct messaging_context
*msg_ctx
;
1535 static struct poptOption long_options
[] = {
1537 { NULL
, '\0', POPT_ARG_INCLUDE_TABLE
, help_options
,
1538 0, "Help options:", NULL
},
1539 { "timeout", 't', POPT_ARG_INT
, &timeout
, 't',
1540 "Set timeout value in seconds", "TIMEOUT" },
1545 TALLOC_CTX
*frame
= talloc_stackframe();
1550 setup_logging(argv
[0], DEBUG_STDOUT
);
1552 /* Parse command line arguments using popt */
1554 pc
= poptGetContext(
1555 "smbcontrol", argc
, (const char **)argv
, long_options
, 0);
1557 poptSetOtherOptionHelp(pc
, "[OPTION...] <destination> <message-type> "
1563 while ((opt
= poptGetNextOpt(pc
)) != -1) {
1565 case 't': /* --timeout */
1568 fprintf(stderr
, "Invalid option\n");
1569 poptPrintHelp(pc
, stderr
, 0);
1574 /* We should now have the remaining command line arguments in
1575 argv. The argc parameter should have been decremented to the
1576 correct value in the above switch statement. */
1578 argv
= (const char **)poptGetArgs(pc
);
1581 while (argv
[argc
] != NULL
) {
1589 lp_load_global(get_dyn_CONFIGFILE());
1591 /* Need to invert sense of return code -- samba
1592 * routines mostly return True==1 for success, but
1595 if (!(evt_ctx
= samba_tevent_context_init(NULL
)) ||
1596 !(msg_ctx
= messaging_init(NULL
, evt_ctx
))) {
1597 fprintf(stderr
, "could not init messaging context\n");
1602 ret
= !do_command(evt_ctx
, msg_ctx
, argc
, argv
);
1603 TALLOC_FREE(msg_ctx
);