summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/configure.in2
-rw-r--r--source3/include/debug.h4
-rw-r--r--source3/include/includes.h6
-rw-r--r--source3/include/messages.h1
-rw-r--r--source3/lib/fault.c97
-rw-r--r--source3/lib/util.c65
-rw-r--r--source3/nmbd/nmbd.c41
-rw-r--r--source3/nsswitch/winbindd.c41
-rw-r--r--source3/printing/printing.c2
-rw-r--r--source3/smbd/open.c4
-rw-r--r--source3/smbd/process.c2
-rw-r--r--source3/smbd/server.c162
-rw-r--r--source3/torture/vfstest.c5
-rw-r--r--source3/utils/smbcontrol.c43
14 files changed, 277 insertions, 198 deletions
diff --git a/source3/configure.in b/source3/configure.in
index 2a3b067da9..f21ee2faa8 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -1470,6 +1470,8 @@ AC_LIBTESTFUNC(sec, bigcrypt)
AC_LIBTESTFUNC(security, getprpwnam)
AC_LIBTESTFUNC(sec, getprpwnam)
+AC_CHECK_FUNCS(strsignal)
+
############################################
# Check if we have libattr
case "$host_os" in
diff --git a/source3/include/debug.h b/source3/include/debug.h
index 2cf1ceaead..ae9fbeba92 100644
--- a/source3/include/debug.h
+++ b/source3/include/debug.h
@@ -208,4 +208,8 @@ extern BOOL *DEBUGLEVEL_CLASS_ISSET;
DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
&& (dbgtext body) )
+/* Print a separator to the debug log. */
+#define DEBUGSEP(level)\
+ DEBUG((level),("===============================================================\n"))
+
#endif
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 620af59db7..7702b6645e 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -1562,5 +1562,9 @@ LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to);
#endif
void smb_panic( const char *why ) NORETURN_ATTRIBUTE ;
-void exit_server(const char *reason) NORETURN_ATTRIBUTE ;
+void dump_core(void) NORETURN_ATTRIBUTE ;
+void exit_server(const char *const reason) NORETURN_ATTRIBUTE ;
+void exit_server_cleanly(void) NORETURN_ATTRIBUTE ;
+void exit_server_fault(void) NORETURN_ATTRIBUTE ;
+
#endif /* _INCLUDES_H */
diff --git a/source3/include/messages.h b/source3/include/messages.h
index dc4f4ca2c0..6a739c0bcc 100644
--- a/source3/include/messages.h
+++ b/source3/include/messages.h
@@ -69,6 +69,7 @@
#define MSG_SMB_OPEN_RETRY 3009
#define MSG_SMB_KERNEL_BREAK 3010
#define MSG_SMB_FILE_RENAME 3011
+#define MSG_SMB_INJECT_FAULT 3012
/* winbind messages */
#define MSG_WINBIND_FINISHED 4001
diff --git a/source3/lib/fault.c b/source3/lib/fault.c
index 3cb6684639..8ae45f2435 100644
--- a/source3/lib/fault.c
+++ b/source3/lib/fault.c
@@ -20,7 +20,12 @@
#include "includes.h"
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
static void (*cont_fn)(void *);
+static pstring corepath;
/*******************************************************************
report a fault
@@ -33,11 +38,11 @@ static void fault_report(int sig)
counter++;
- DEBUG(0,("===============================================================\n"));
+ DEBUGSEP(0);
DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),SAMBA_VERSION_STRING));
DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
- DEBUG(0,("===============================================================\n"));
+ DEBUGSEP(0);
smb_panic("internal error");
@@ -82,3 +87,91 @@ void fault_setup(void (*fn)(void *))
CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
#endif
}
+
+/*******************************************************************
+make all the preparations to safely dump a core file
+********************************************************************/
+
+void dump_core_setup(const char *progname)
+{
+ pstring logbase;
+ char * end;
+
+ if (lp_logfile() && *lp_logfile()) {
+ snprintf(logbase, sizeof(logbase), "%s", lp_logfile());
+ if ((end = strrchr_m(logbase, '/'))) {
+ *end = '\0';
+ }
+ } else {
+ /* We will end up here is the log file is given on the command
+ * line by the -l option but the "log file" option is not set
+ * in smb.conf.
+ */
+ snprintf(logbase, sizeof(logbase), "%s", dyn_LOGFILEBASE);
+ }
+
+ SMB_ASSERT(progname != NULL);
+
+ snprintf(corepath, sizeof(corepath), "%s/cores", logbase);
+ mkdir(corepath,0700);
+
+ snprintf(corepath, sizeof(corepath), "%s/cores/%s",
+ logbase, progname);
+ mkdir(corepath,0700);
+
+ sys_chown(corepath,getuid(),getgid());
+ chmod(corepath,0700);
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(16*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Maximum core file size limits now %d(soft) %d(hard)\n",
+ (int)rlp.rlim_cur,(int)rlp.rlim_max));
+ }
+#endif
+#endif
+
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ /* On Linux we lose the ability to dump core when we change our user
+ * ID. We know how to dump core safely, so let's make sure we have our
+ * dumpable flag set.
+ */
+ prctl(PR_SET_DUMPABLE, 1);
+#endif
+
+ /* FIXME: if we have a core-plus-pid facility, configurably set
+ * this up here.
+ */
+}
+
+ void dump_core(void)
+{
+ if (*corepath != '\0') {
+ /* The chdir might fail if we dump core before we finish
+ * processing the config file.
+ */
+ if (chdir(corepath) != 0) {
+ DEBUG(0, ("unable to change to %s", corepath));
+ DEBUGADD(0, ("refusing to dump core\n"));
+ exit(1);
+ }
+
+ DEBUG(0,("dumping core in %s\n", corepath));
+ }
+
+ umask(~(0700));
+ dbgflush();
+
+ /* Ensure we don't have a signal handler for abort. */
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
+
+ abort();
+}
+
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 0b831ea335..0fbe4a13d3 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1545,19 +1545,10 @@ gid_t nametogid(const char *name)
Something really nasty happened - panic !
********************************************************************/
-#ifdef HAVE_LIBEXC_H
-#include <libexc.h>
-#endif
-
-static void smb_panic2(const char *why, BOOL decrement_pid_count )
+void smb_panic(const char *const why)
{
char *cmd;
int result;
-#ifdef HAVE_BACKTRACE_SYMBOLS
- void *backtrace_stack[BACKTRACE_STACK_SIZE];
- size_t backtrace_size;
- char **backtrace_strings;
-#endif
#ifdef DEVELOPER
{
@@ -1570,9 +1561,12 @@ static void smb_panic2(const char *why, BOOL decrement_pid_count )
}
#endif
+ DEBUG(0,("PANIC (pid %llu): %s\n",
+ (unsigned long long)sys_getpid(), why));
+ log_stack_trace();
+
/* only smbd needs to decrement the smbd counter in connections.tdb */
- if ( decrement_pid_count )
- decrement_smbd_process_count();
+ decrement_smbd_process_count();
cmd = lp_panic_action();
if (cmd && *cmd) {
@@ -1586,9 +1580,27 @@ static void smb_panic2(const char *why, BOOL decrement_pid_count )
DEBUG(0, ("smb_panic(): action returned status %d\n",
WEXITSTATUS(result)));
}
- DEBUG(0,("PANIC: %s\n", why));
+ dump_core();
+}
+
+/*******************************************************************
+ Print a backtrace of the stack to the debug log. This function
+ DELIBERATELY LEAKS MEMORY. The expectation is that you should
+ exit shortly after calling it.
+********************************************************************/
+
+#ifdef HAVE_LIBEXC_H
+#include <libexc.h>
+#endif
+
+void log_stack_trace(void)
+{
#ifdef HAVE_BACKTRACE_SYMBOLS
+ void *backtrace_stack[BACKTRACE_STACK_SIZE];
+ size_t backtrace_size;
+ char **backtrace_strings;
+
/* get the backtrace (stack frames) */
backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
@@ -1607,16 +1619,14 @@ static void smb_panic2(const char *why, BOOL decrement_pid_count )
#elif HAVE_LIBEXC
-#define NAMESIZE 32 /* Arbitrary */
-
/* The IRIX libexc library provides an API for unwinding the stack. See
* libexc(3) for details. Apparantly trace_back_stack leaks memory, but
* since we are about to abort anyway, it hardly matters.
- *
- * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
- * will fail with a nasty message upon failing to open the /proc entry.
*/
{
+
+#define NAMESIZE 32 /* Arbitrary */
+
__uint64_t addrs[BACKTRACE_STACK_SIZE];
char * names[BACKTRACE_STACK_SIZE];
char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
@@ -1646,24 +1656,9 @@ static void smb_panic2(const char *why, BOOL decrement_pid_count )
}
}
#undef NAMESIZE
+#else
+ DEBUG(0, ("unable to produce a stack trace on this platform\n"));
#endif
-
- dbgflush();
-#ifdef SIGABRT
- CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
-#endif
- abort();
-}
-
-/*******************************************************************
- wrapper for smb_panic2()
-********************************************************************/
-
- void smb_panic( const char *why )
-{
- smb_panic2( why, True );
- /* Notreached. */
- abort();
}
/*******************************************************************
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index f58c389fc9..fca17d1ff7 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -106,46 +106,6 @@ static void sig_hup(int sig)
sys_select_signal(SIGHUP);
}
-#if DUMP_CORE
-/**************************************************************************** **
- Prepare to dump a core file - carefully!
- **************************************************************************** */
-
-static BOOL dump_core(void)
-{
- char *p;
- pstring dname;
- pstrcpy( dname, lp_logfile() );
- if ((p=strrchr_m(dname,'/')))
- *p=0;
- pstrcat( dname, "/corefiles" );
- mkdir( dname, 0700 );
- sys_chown( dname, getuid(), getgid() );
- chmod( dname, 0700 );
- if ( chdir(dname) )
- return( False );
- umask( ~(0700) );
-
-#ifdef HAVE_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit( RLIMIT_CORE, &rlp );
- rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
- setrlimit( RLIMIT_CORE, &rlp );
- getrlimit( RLIMIT_CORE, &rlp );
- DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
- }
-#endif
-#endif
-
-
- DEBUG(0,("Dumping core in %s\n",dname));
- abort();
- return( True );
-}
-#endif
-
/**************************************************************************** **
Possibly continue after a fault.
**************************************************************************** */
@@ -692,6 +652,7 @@ static BOOL open_sockets(BOOL isdaemon, int port)
}
fault_setup((void (*)(void *))fault_continue );
+ dump_core_setup("nmbd");
/* POSIX demands that signals are inherited. If the invoking process has
* these signals masked, we will have problems, as we won't receive them. */
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index ad2774eea6..b318416272 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -56,46 +56,6 @@ static BOOL reload_services_file(void)
}
-#if DUMP_CORE
-
-/**************************************************************************** **
- Prepare to dump a core file - carefully!
- **************************************************************************** */
-
-static BOOL dump_core(void)
-{
- char *p;
- pstring dname;
- pstrcpy( dname, lp_logfile() );
- if ((p=strrchr(dname,'/')))
- *p=0;
- pstrcat( dname, "/corefiles" );
- mkdir( dname, 0700 );
- sys_chown( dname, getuid(), getgid() );
- chmod( dname, 0700 );
- if ( chdir(dname) )
- return( False );
- umask( ~(0700) );
-
-#ifdef HAVE_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit( RLIMIT_CORE, &rlp );
- rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
- setrlimit( RLIMIT_CORE, &rlp );
- getrlimit( RLIMIT_CORE, &rlp );
- DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
- }
-#endif
-#endif
-
- DEBUG(0,("Dumping core in %s\n",dname));
- abort();
- return( True );
-} /* dump_core */
-#endif
-
/**************************************************************************** **
Handle a fault..
**************************************************************************** */
@@ -933,6 +893,7 @@ int main(int argc, char **argv)
CatchSignal(SIGUSR2, SIG_IGN);
fault_setup((void (*)(void *))fault_quit );
+ dump_core_setup("winbindd");
load_case_tables();
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
index 452031368d..0448eac3cd 100644
--- a/source3/printing/printing.c
+++ b/source3/printing/printing.c
@@ -1400,7 +1400,7 @@ void start_background_queue(void)
/* check for some essential signals first */
if (got_sig_term) {
- exit_server("Caught TERM signal");
+ exit_server_cleanly();
}
if (reload_after_sighup) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index ba0a16035a..99a7894762 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -724,7 +724,7 @@ static void defer_open(struct share_mode_lock *lck,
if (procid_is_me(&e->pid) && (e->op_mid == mid)) {
DEBUG(0, ("Trying to defer an already deferred "
"request: mid=%d, exiting\n", mid));
- exit_server("exiting");
+ exit_server("attempt to defer a deferred request");
}
}
@@ -738,7 +738,7 @@ static void defer_open(struct share_mode_lock *lck,
if (!push_deferred_smb_message(mid, request_time, timeout,
(char *)state, sizeof(*state))) {
- exit_server("push_deferred_smb_message failed\n");
+ exit_server("push_deferred_smb_message failed");
}
add_deferred_open(lck, mid, request_time, state->dev, state->inode);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 7ec08cb4a7..40d26f7672 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -303,7 +303,7 @@ static void async_processing(fd_set *pfds)
process_aio_queue();
if (got_sig_term) {
- exit_server("Caught TERM signal");
+ exit_server_cleanly();
}
/* check for async change notify events */
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 4d737d2849..dfead851e8 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -22,10 +22,6 @@
#include "includes.h"
-#ifdef HAVE_SYS_PRCTL_H
-#include <sys/prctl.h>
-#endif
-
static int am_parent = 1;
/* the last message the was processed */
@@ -156,8 +152,40 @@ static BOOL open_sockets_inetd(void)
static void msg_exit_server(int msg_type, struct process_id src,
void *buf, size_t len)
{
- exit_server("Got a SHUTDOWN message");
+ DEBUG(3, ("got a SHUTDOWN message\n"));
+ exit_server_cleanly();
+}
+
+#ifdef DEVELOPER
+static void msg_inject_fault(int msg_type, struct process_id src,
+ void *buf, size_t len)
+{
+ int sig;
+
+ if (len != sizeof(int)) {
+
+ DEBUG(0, ("Process %llu sent bogus signal injection request\n",
+ (unsigned long long)src.pid));
+ return;
+ }
+
+ sig = *(int *)buf;
+ if (sig == -1) {
+ exit_server("internal error injected");
+ return;
+ }
+
+#if HAVE_STRSIGNAL
+ DEBUG(0, ("Process %llu requested injection of signal %d (%s)\n",
+ (unsigned long long)src.pid, sig, strsignal(sig)));
+#else
+ DEBUG(0, ("Process %llu requested injection of signal %d\n",
+ (unsigned long long)src.pid, sig));
+#endif
+
+ kill(sys_getpid(), sig);
}
+#endif /* DEVELOPER */
/****************************************************************************
@@ -345,6 +373,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed);
message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated);
+#ifdef DEVELOPER
+ message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault);
+#endif
+
/* now accept incoming connections - forking a new process
for each incoming connection */
DEBUG(2,("waiting for a connection\n"));
@@ -365,7 +397,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
if (num == -1 && errno == EINTR) {
if (got_sig_term) {
- exit_server("Caught TERM signal");
+ exit_server_cleanly();
}
/* check for sighup processing */
@@ -568,60 +600,18 @@ BOOL reload_services(BOOL test)
return(ret);
}
-
-#if DUMP_CORE
-
-static void dump_core(void) NORETURN_ATTRIBUTE ;
-
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
-
-static void dump_core(void)
-{
- char *p;
- pstring dname;
-
- pstrcpy(dname,lp_logfile());
- if ((p=strrchr_m(dname,'/'))) *p=0;
- pstrcat(dname,"/corefiles");
- mkdir(dname,0700);
- sys_chown(dname,getuid(),getgid());
- chmod(dname,0700);
- if (chdir(dname)) {
- abort();
- }
- umask(~(0700));
-
-#ifdef HAVE_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit(RLIMIT_CORE, &rlp);
- rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
- setrlimit(RLIMIT_CORE, &rlp);
- getrlimit(RLIMIT_CORE, &rlp);
- DEBUG(3,("Core limits now %d %d\n",
- (int)rlp.rlim_cur,(int)rlp.rlim_max));
- }
-#endif
-#endif
-
-
- DEBUG(0,("Dumping core in %s\n", dname));
- /* Ensure we don't have a signal handler for abort. */
-#ifdef SIGABRT
- CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
-#endif
- abort();
-}
-#endif
-
/****************************************************************************
Exit the server.
****************************************************************************/
- void exit_server(const char *reason)
+/* Reasons for shutting down a server process. */
+enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
+
+static void exit_server_common(enum server_exit_reason how,
+ const char *const reason) NORETURN_ATTRIBUTE;
+
+static void exit_server_common(enum server_exit_reason how,
+ const char *const reason)
{
static int firsttime=1;
@@ -630,7 +620,6 @@ static void dump_core(void)
firsttime = 0;
change_to_root_user();
- DEBUG(2,("Closing connections\n"));
if (negprot_global_auth_context) {
(negprot_global_auth_context->free)(&negprot_global_auth_context);
@@ -654,27 +643,54 @@ static void dump_core(void)
}
#endif
- if (!reason) {
+ locking_end();
+ printing_end();
+
+ if (how != SERVER_EXIT_NORMAL) {
int oldlevel = DEBUGLEVEL;
char *last_inbuf = get_InBuffer();
+
DEBUGLEVEL = 10;
- DEBUG(0,("Last message was %s\n",smb_fn_name(last_message)));
- if (last_inbuf)
+
+ DEBUGSEP(0);
+ DEBUG(0,("Abnormal server exit: %s\n",
+ reason ? reason : "no explanation provided"));
+ DEBUGSEP(0);
+
+ log_stack_trace();
+ if (last_inbuf) {
+ DEBUG(0,("Last message was %s\n", LAST_MESSAGE()));
show_msg(last_inbuf);
+ }
+
DEBUGLEVEL = oldlevel;
- DEBUG(0,("===============================================================\n"));
#if DUMP_CORE
dump_core();
#endif
- }
- locking_end();
- printing_end();
+ } else {
+ DEBUG(3,("Server exit (%s)\n",
+ (reason ? reason : "normal exit")));
+ }
- DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
exit(0);
}
+void exit_server(const char *const explanation)
+{
+ exit_server_common(SERVER_EXIT_ABNORMAL, explanation);
+}
+
+void exit_server_cleanly(void)
+{
+ exit_server_common(SERVER_EXIT_NORMAL, NULL);
+}
+
+void exit_server_fault(void)
+{
+ exit_server("critical server fault");
+}
+
/****************************************************************************
Initialise connect, service and file structs.
****************************************************************************/
@@ -795,7 +811,9 @@ void build_options(BOOL screen);
gain_root_privilege();
gain_root_group_privilege();
- fault_setup((void (*)(void *))exit_server);
+ fault_setup((void (*)(void *))exit_server_fault);
+ dump_core_setup("smbd");
+
CatchSignal(SIGTERM , SIGNAL_CAST sig_term);
CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
@@ -948,14 +966,6 @@ void build_options(BOOL screen);
* everything after this point is run after the fork()
*/
-#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
- /* On Linux we lose the ability to dump core when we change our user
- * ID. We know how to dump core safely, so let's make sure we have our
- * dumpable flag set.
- */
- prctl(PR_SET_DUMPABLE, 1);
-#endif
-
/* Initialise the password backed before the global_sam_sid
to ensure that we fetch from ldap before we make a domain sid up */
@@ -1002,9 +1012,9 @@ void build_options(BOOL screen);
message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis);
smbd_process();
-
+
namecache_shutdown();
- exit_server("normal exit");
+ exit_server_cleanly();
return(0);
}
diff --git a/source3/torture/vfstest.c b/source3/torture/vfstest.c
index 023e656c67..e83b12aa9d 100644
--- a/source3/torture/vfstest.c
+++ b/source3/torture/vfstest.c
@@ -410,6 +410,11 @@ void exit_server(const char *reason)
exit(0);
}
+void exit_server_cleanly(void)
+{
+ exit_server("normal exit");
+}
+
static int server_fd = -1;
int last_message = -1;
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index 76d699c54f..302303b3cd 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -131,6 +131,47 @@ static BOOL do_debug(const struct process_id pid,
pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
}
+/* Inject a fault (fata signal) into a running smbd */
+
+static BOOL do_inject_fault(const struct process_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> inject "
+ "<bus|hup|term|internal|segv>\n");
+ return False;
+ }
+
+#ifndef DEVELOPER
+ fprintf(stderr, "Fault injection is only available in"
+ "developer builds\n")
+ return False;
+#else /* DEVELOPER */
+ {
+ int sig = 0;
+
+ if (strcmp(argv[1], "bus") == 0) {
+ sig = SIGBUS;
+ } else if (strcmp(argv[1], "hup") == 0) {
+ sig = SIGHUP;
+ } else if (strcmp(argv[1], "term") == 0) {
+ sig = SIGTERM;
+ } else if (strcmp(argv[1], "segv") == 0) {
+ sig = SIGSEGV;
+ } else if (strcmp(argv[1], "internal") == 0) {
+ /* Force an internal error, ie. an unclean exit. */
+ sig = -1;
+ } else {
+ fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
+ return False;
+ }
+
+ return send_message(pid, MSG_SMB_INJECT_FAULT,
+ &sig, sizeof(int), False);
+ }
+#endif /* DEVELOPER */
+}
+
/* Force a browser election */
static BOOL do_election(const struct process_id pid,
@@ -756,6 +797,8 @@ static const struct {
"Force a browse election" },
{ "ping", do_ping, "Elicit a response" },
{ "profile", do_profile, "" },
+ { "inject", do_inject_fault,
+ "Inject a fatal signal into a running smbd"},
{ "profilelevel", do_profilelevel, "" },
{ "debuglevel", do_debuglevel, "Display current debuglevels" },
{ "printnotify", do_printnotify, "Send a print notify message" },