diff options
author | dd <dd@FreeBSD.org> | 2001-11-27 19:56:28 +0000 |
---|---|---|
committer | dd <dd@FreeBSD.org> | 2001-11-27 19:56:28 +0000 |
commit | da78f952f391aa86cf6f5b9b872501bc7d130c35 (patch) | |
tree | 5e0f8766c5361fccec64230a053d2af21500b83b /sys/ddb/db_command.c | |
parent | 05ebaf9058f8cc353ae570684d94fcadd1320fb0 (diff) | |
download | FreeBSD-src-da78f952f391aa86cf6f5b9b872501bc7d130c35.zip FreeBSD-src-da78f952f391aa86cf6f5b9b872501bc7d130c35.tar.gz |
Implement a "kill" DDB command which is an interface to psignal() that
respects locks. Before SMPng, one was able to call psignal()
using the "call" command, but this is no longer possible because it
does not respect locks by itself. This is very useful when one has
gotten their machine into a state where it is impossible to spawn
ps/kill or su to root.
In this case, respecting locks essentially means trying to aquire the
proc lock before calling psignal(). We can't block in the debugger,
so if trylock fails, the operation fails. This also means that we
can't use pfind(), since that will attempt to lock the process for us.
Reviewed by: jhb
Diffstat (limited to 'sys/ddb/db_command.c')
-rw-r--r-- | sys/ddb/db_command.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index 57b722b..dfbdc10 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -36,7 +36,11 @@ */ #include <sys/param.h> #include <sys/linker_set.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> #include <sys/reboot.h> +#include <sys/signalvar.h> #include <sys/systm.h> #include <sys/cons.h> @@ -63,6 +67,7 @@ SET_DECLARE(db_show_cmd_set, struct command); static db_cmdfcn_t db_fncall; static db_cmdfcn_t db_gdb; +static db_cmdfcn_t db_kill; static db_cmdfcn_t db_reset; /* XXX this is actually forward-static. */ @@ -418,6 +423,7 @@ static struct command db_command_table[] = { { "ps", db_ps, 0, 0 }, { "gdb", db_gdb, 0, 0 }, { "reset", db_reset, 0, 0 }, + { "kill", db_kill, CS_OWN, 0 }, { (char *)0, } }; @@ -574,6 +580,59 @@ db_gdb (dummy1, dummy2, dummy3, dummy4) } static void +db_kill(dummy1, dummy2, dummy3, dummy4) + db_expr_t dummy1; + boolean_t dummy2; + db_expr_t dummy3; + char * dummy4; +{ + db_expr_t old_radix, pid, sig; + struct proc *p; + +#define DB_ERROR(f) do { db_printf f; db_flush_lex(); goto out; } while (0) + + /* + * PIDs and signal numbers are typically represented in base + * 10, so make that the default here. It can, of course, be + * overridden by specifying a prefix. + */ + old_radix = db_radix; + db_radix = 10; + /* Retrieve arguments. */ + if (!db_expression(&sig)) + DB_ERROR(("Missing signal number\n")); + if (!db_expression(&pid)) + DB_ERROR(("Missing process ID\n")); + db_skip_to_eol(); + if (sig < 0 || sig > _SIG_MAXSIG) + DB_ERROR(("Signal number out of range\n")); + + /* + * Find the process in question. allproc_lock is not needed + * since we're in DDB. + */ + /* sx_slock(&allproc_lock); */ + LIST_FOREACH(p, &allproc, p_list) + if (p->p_pid == pid) + break; + /* sx_sunlock(&allproc_lock); */ + if (p == NULL) + DB_ERROR(("Can't find process with pid %d\n", pid)); + + /* If it's already locked, bail; otherwise, do the deed. */ + if (PROC_TRYLOCK(p) == 0) + DB_ERROR(("Can't lock process with pid %d\n", pid)); + else { + psignal(p, sig); + PROC_UNLOCK(p); + } + +out: + db_radix = old_radix; +#undef DB_ERROR +} + +static void db_reset(dummy1, dummy2, dummy3, dummy4) db_expr_t dummy1; boolean_t dummy2; |