diff options
Diffstat (limited to 'trans/crash.c')
-rw-r--r-- | trans/crash.c | 230 |
1 files changed, 203 insertions, 27 deletions
diff --git a/trans/crash.c b/trans/crash.c index 5947cb26..4a59d450 100644 --- a/trans/crash.c +++ b/trans/crash.c @@ -1,5 +1,8 @@ /* GNU Hurd standard crash dump server. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Copyright (C) 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2006, 2007 + Free Software Foundation, Inc. + Written by Roland McGrath. This file is part of the GNU Hurd. @@ -23,12 +26,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd/trivfs.h> #include <sys/wait.h> #include <error.h> +#include <argp.h> +#include <argz.h> +#include <sys/mman.h> + +#include <version.h> #include "crash_S.h" #include "crash_reply_U.h" #include "msg_S.h" +const char *argp_program_version = STANDARD_HURD_VERSION (crash); + process_t procserver; /* Our proc port, for easy access. */ /* Port bucket we service requests on. */ @@ -49,6 +59,23 @@ int trivfs_cntl_nportclasses = 1; struct trivfs_control *fsys; +enum crash_action +{ + crash_unspecified, + crash_suspend, + crash_kill, + crash_corefile +}; +#define CRASH_DEFAULT crash_suspend +#define CRASH_ORPHANS_DEFAULT crash_corefile + +static enum crash_action crash_how, crash_orphans_how; + + +/* This is defined in ../exec/elfcore.c, or we could have + different implementations for other formats. */ +extern error_t dump_core (task_t task, file_t file, off_t corelimit, + int signo, long int sigcode, int sigerror); /* This data structure describes a crashing task which we have suspended. This is attached to a receive right we have set as the process's message @@ -67,6 +94,7 @@ struct crasher task_t task; file_t core_file; + off_t core_limit; int signo, sigcode, sigerror; mach_port_t original_msgport; /* Restore on resume. */ @@ -100,7 +128,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid) err = proc_getpgrppids (userproc, pgrp, &pids, &numpids); if (err) return; - + for (i = 0; i < numpids; i++) if (pids[i] != pid) { @@ -111,7 +139,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid) mach_port_deallocate (mach_task_self (), msgport); } if (pids != pids_) - vm_deallocate (mach_task_self (), (vm_address_t) pids, numpids); + munmap (pids, numpids); } @@ -119,25 +147,48 @@ kern_return_t S_crash_dump_task (mach_port_t port, mach_port_t reply_port, mach_msg_type_name_t reply_type, task_t task, file_t core_file, - int signo, int sigcode, int sigerror, + int signo, integer_t sigcode, int sigerror, natural_t exc, natural_t code, natural_t subcode, mach_port_t ctty_id) - { error_t err; struct trivfs_protid *cred; - mach_port_t user_proc; + mach_port_t user_proc = MACH_PORT_NULL; + enum crash_action how; cred = ports_lookup_port (port_bucket, port, trivfs_protid_portclasses[0]); if (! cred) return EOPNOTSUPP; - /* Suspend the task first thing before being twiddling it. */ - err = task_suspend (task); - - if (! err) + how = crash_how; + if (crash_how != crash_orphans_how) { + /* We must ascertain if this is an orphan before deciding what to do. */ err = proc_task2proc (procserver, task, &user_proc); + if (!err) + { + pid_t pid, ppid; + int orphan; + err = proc_getpids (user_proc, &pid, &ppid, &orphan); + if (!err && orphan) + how = crash_orphans_how; + } + } + + switch (how) + { + default: /* NOTREACHED */ + err = EGRATUITOUS; + break; + + case crash_suspend: + /* Suspend the task first thing before being twiddling it. */ + err = task_suspend (task); + if (err) + break; + + if (user_proc != MACH_PORT_NULL) + err = proc_task2proc (procserver, task, &user_proc); if (! err) { struct crasher *c; @@ -152,9 +203,7 @@ S_crash_dump_task (mach_port_t port, /* Install our port as the crasher's msgport. We will wait for signals to resume (crash) it. */ - msgport = ports_get_right (c); - mach_port_insert_right (mach_task_self (), msgport, - msgport, MACH_MSG_TYPE_MAKE_SEND); + msgport = ports_get_send_right (c); err = proc_setmsgport (user_proc, msgport, &c->original_msgport); mach_port_deallocate (mach_task_self (), msgport); @@ -169,6 +218,7 @@ S_crash_dump_task (mach_port_t port, c->task = task; c->core_file = core_file; + c->core_limit = (off_t) -1; /* XXX should core limit in RPC */ c->signo = signo; c->sigcode = sigcode; c->sigerror = sigerror; @@ -179,7 +229,40 @@ S_crash_dump_task (mach_port_t port, } if (err != MIG_NO_REPLY) task_resume (task); + break; + + case crash_corefile: + err = task_suspend (task); + if (!err) + { + err = dump_core (task, core_file, + (off_t) -1, /* XXX should get core limit in RPC */ + signo, sigcode, sigerror); + task_resume (task); + } + break; + + case crash_kill: + { + if (user_proc != MACH_PORT_NULL) + err = 0; + else + err = proc_task2proc (procserver, task, &user_proc); + if (!err) + err = proc_mark_exit (user_proc, W_EXITCODE (0, signo), sigcode); + err = task_terminate (task); + if (!err) + { + mach_port_deallocate (mach_task_self (), task); + mach_port_deallocate (mach_task_self (), core_file); + mach_port_deallocate (mach_task_self (), ctty_id); + } + } } + + if (user_proc != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), user_proc); + ports_port_deref (cred); return err; } @@ -294,13 +377,6 @@ S_msg_sig_post_untraced (mach_port_t port, return err; } -error_t -dump_core (task_t task, file_t core_file, - int signo, long int sigcode, int sigerror) -{ - return ENOSYS; /* XXX */ -} - /* This gets called when the receive right for a crasher message port dies. */ void @@ -319,7 +395,7 @@ dead_crasher (void *ptr) { /* C->proc was cleared in S_msg_sig_post as a marker that this crasher should get a core dump when we clean him up. */ - error_t err = dump_core (c->task, c->core_file, + error_t err = dump_core (c->task, c->core_file, c->core_limit, c->signo, c->sigcode, c->sigerror); /* Now reply to the crasher's original RPC which started this whole party. He should now report his own death (with core dump iff ERR @@ -358,6 +434,109 @@ dead_crasher (void *ptr) } +static const struct argp_option options[] = +{ + {0,0,0,0,"These options specify the disposition of a crashing process:", 1}, + {"action", 'a', "ACTION", 0, "Action taken on crashing processes", 1}, + {"orphan-action", 'O', "ACTION", 0, "Action taken on crashing orphans", 1}, + + {0,0,0,0,"These options are synonyms for --action=OPTION:", 2}, + {"suspend", 's', 0, 0, "Suspend the process", 2}, + {"kill", 'k', 0, 0, "Kill the process", 2}, + {"core-file", 'c', 0, 0, "Dump a core file", 2}, + {"dump-core", 0, 0, OPTION_ALIAS }, + {0} +}; +static const char doc[] = +"Server to handle crashing tasks and dump core files or equivalent.\v" +"The ACTION values can be `suspend', `kill', or `core-file'.\n\n" +"If `--orphan-action' is not specified, the `--action' value is used for " +"orphans. The default is `--action=suspend --orphan-action=core-file'."; + +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + error_t parse_action (enum crash_action *how) + { + if (!strcmp (arg, "suspend")) + *how = crash_suspend; + else if (!strcmp (arg, "kill")) + *how = crash_kill; + else if (!strcmp (arg, "core-file")) + *how = crash_corefile; + else + { + argp_error (state, + "action must be one of: suspend, kill, core-file"); + return EINVAL; + } + return 0; + } + + switch (opt) + { + default: + return ARGP_ERR_UNKNOWN; + case ARGP_KEY_INIT: + case ARGP_KEY_ERROR: + break; + + case 'a': + return parse_action (&crash_how); + case 'O': + return parse_action (&crash_orphans_how); + + case 's': crash_how = crash_suspend; break; + case 'k': crash_how = crash_kill; break; + case 'c': crash_how = crash_corefile; break; + + case ARGP_KEY_SUCCESS: + if (crash_orphans_how == crash_unspecified) + crash_orphans_how = (crash_how == crash_unspecified + ? CRASH_ORPHANS_DEFAULT : crash_how); + if (crash_how == crash_unspecified) + crash_how = CRASH_DEFAULT; + break; + } + return 0; +} + +error_t +trivfs_append_args (struct trivfs_control *fsys, + char **argz, size_t *argz_len) +{ + error_t err; + const char *opt; + + switch (crash_how) + { + case crash_suspend: opt = "--action=suspend"; break; + case crash_kill: opt = "--action=kill"; break; + case crash_corefile: opt = "--action=core-file"; break; + default: + return EGRATUITOUS; + } + err = argz_add (argz, argz_len, opt); + + if (!err) + { + switch (crash_orphans_how) + { + case crash_suspend: opt = "--orphan-action=suspend"; break; + case crash_kill: opt = "--orphan-action=kill"; break; + case crash_corefile: opt = "--orphan-action=core-file"; break; + default: + return EGRATUITOUS; + } + err = argz_add (argz, argz_len, opt); + } + + return err; +} + +struct argp crash_argp = { options, parse_opt, 0, doc }; +struct argp *trivfs_runtime_argp = &crash_argp; + static int crash_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) @@ -375,6 +554,7 @@ main (int argc, char **argv) error_t err; mach_port_t bootstrap; + argp_parse (&crash_argp, argc, argv, 0,0,0); task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) @@ -402,7 +582,7 @@ main (int argc, char **argv) ports_manage_port_operations_multithread (port_bucket, crash_demuxer, 10 * 1000, /* idle thread */ 10 * 60 * 1000, /* idle server */ - 0, MACH_PORT_NULL); + 0); /* That returns when 10 minutes pass without an RPC. Try shutting down as if sent fsys_goaway; if we have any users who need us to stay around, this returns EBUSY and we loop to service more RPCs. */ @@ -414,7 +594,6 @@ main (int argc, char **argv) void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { - st->st_fstype = FSTYPE_MISC; } error_t @@ -598,9 +777,6 @@ S_msg_set_env_variable (mach_port_t process, boolean_t replace) { return EBUSY; } kern_return_t -S_msg_startup_dosync (mach_port_t process) -{ return EBUSY; } -kern_return_t S_msg_get_exec_flags (mach_port_t process, mach_port_t refport, int *flags) { return EBUSY; } kern_return_t @@ -615,7 +791,7 @@ S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t refport, { return EBUSY; } error_t S_msg_report_wait (mach_port_t process, thread_t thread, - string_t desc, int *rpc) + string_t desc, mach_msg_id_t *rpc) { return EBUSY; } error_t S_msg_describe_ports (mach_port_t msgport, mach_port_t refport, |