From 4fa555980070d78b39711ef21d77628d26055bc2 Mon Sep 17 00:00:00 2001 From: James Peach Date: Tue, 4 Apr 2006 00:27:50 +0000 Subject: r14898: This change is an attempt to improve the quality of the information that is produced when a process exits abnormally. First, we coalesce the core dumping code so that we greatly improve our odds of being able to produce a core file, even in the case of a memory fault. I've removed duplicates of dump_core() and split it in two to reduce the amount of work needed to actually do the dump. Second, we refactor the exit_server code path to always log an explanation and a stack trace. My goal is to always produce enough log information for us to be able to explain any server exit, though there is a risk that this could produce too much log information on a flaky network. Finally, smbcontrol has gained a smbd fault injection operation to test the changes above. This is only enabled for developer builds. (This used to be commit 56bc02d64498eb3faf89f0c5452b9299daea8e95) --- source3/configure.in | 2 + source3/include/debug.h | 4 ++ source3/include/includes.h | 6 +- source3/include/messages.h | 1 + source3/lib/fault.c | 97 +++++++++++++++++++++++++- source3/lib/util.c | 65 ++++++++---------- source3/nmbd/nmbd.c | 41 +---------- source3/nsswitch/winbindd.c | 41 +---------- source3/printing/printing.c | 2 +- source3/smbd/open.c | 4 +- source3/smbd/process.c | 2 +- source3/smbd/server.c | 162 +++++++++++++++++++++++--------------------- source3/torture/vfstest.c | 5 ++ source3/utils/smbcontrol.c | 43 ++++++++++++ 14 files changed, 277 insertions(+), 198 deletions(-) (limited to 'source3') 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 +#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 -#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 +#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 -#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 inject " + "\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" }, -- cgit