summaryrefslogtreecommitdiff
path: root/trans/crash.c
diff options
context:
space:
mode:
Diffstat (limited to 'trans/crash.c')
-rw-r--r--trans/crash.c230
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,