From 887d8b57c4aa291919c8eec6b2af5a5f5259ac6d Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Mon, 17 May 2004 17:52:45 +0000 Subject: Initial 5.2.x files --- srcx/jkill.c | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 srcx/jkill.c (limited to 'srcx/jkill.c') diff --git a/srcx/jkill.c b/srcx/jkill.c new file mode 100644 index 0000000..46b1815 --- /dev/null +++ b/srcx/jkill.c @@ -0,0 +1,283 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +/* The timeout to wait between kills */ +#define DEFAULT_TIMEOUT 3 +int g_timeout = DEFAULT_TIMEOUT; + +/* Supress warnings */ +int g_quiet = 0; + +int main(int argc, char* argv[]) +{ + int ch, r, jid; + int ret = 0; + int restart = 0; + int force = 0; + pid_t child; + + while((ch = getopt(argc, argv, "fhqrt:")) != -1) + { + switch(ch) + { + case 'f': + force = 1; + break; + + case 'q': + g_quiet = 1; + break; + + case 'h': + /* dummy for compatibility with killjail */ + warnx("the '-h' option has been depreciated"); + break; + + case 'r': + restart = 1; + break; + + /* Timeout to use between kills */ + case 't': + g_timeout = atoi(optarg); + if(g_timeout <= 0) + errx(2, "invalid timeout argument: %s", optarg); + break; + + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + /* Make sure we have a jail id or name */ + if(argc == 0) + usage(); + + /* For each jail */ + while(argc > 0) + { + jid = translate_jail(argv[0]); + if(jid == -1) + { + warnx(1, "unknown jail host name: %s", argv[0]); + ret = 1; + continue; + } + + /* + * We fork and the child goes into the jail and + * does the dirty work. + */ + + switch((child = fork())) + { + /* Error condition */ + case -1: + err(1, "couldn't fork child process"); + break; + + /* The child */ + case 0: + if(jail_attach(jid) == -1) + err(1, "couldn't attach to jail"); + + r = kill_jail(restart, force, argv[0]); + exit(r); + break; + + /* The parent */ + default: + if(waitpid(child, &r, options) == -1) + err(1, "error waiting for child process"); + + if(r != 0) + ret = r; + break; + }; + + argc--; + argv++; + } + + return ret; +} + +int kill_jail(int restart, int force, const char* name) +{ + kvm_t* kd = NULL; + char errbuf[_POSIX2_LINE_MAX]; + int pass = 0; + int timeout = 0; + int ret = 0; + + /* Open the kernel interface */ + kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, + O_RDONLY, errbuf); + if(kd == NULL) + errx(1, "couldn't connect to kernel: %s", errbuf); + + /* + * Multiple passes are used to do different things. + * Each time the jails processes are listed. + */ + while(true) + { + while(timeout > 0) + { + sleep(1); + timeout--; + + if(!check_running_processes(kd)) + goto done; + } + + switch(pass) + { + /* First pass is an orderly shutdown */ + case 0: + + /* Check if we have an executable shutdown script */ + if(check_jail_command(name, "/etc/rc.shutdown")) + run_jail_command(name, "/etc/rc.shutdown", NULL, JAIL_OUT_CONSOLE); + + break; + + /* Okay now quit all processes in jail */ + case 1: + kill_jail_processes(kd, SIGTERM); + timeout = g_timeout; + break; + + /* Okay now we force kill the processes if necessary */ + case 2: + + if(force) + { + /* If we get here, jailer looks like it's really irresponsive */ + if(!g_quiet) + warnx("%s: jail won't stop. forcing jail termination...", name); + + kill_jail_processes(kd, SIGKILL); + timeout = g_timeout; + } + + break; + + + case 3: + + if(check_running_processes(kd)) + { + /* And if that didn't do it, well then give up */ + if(!g_quiet) + warnx("%s: couldn't stop jail, processes wouldn't die", name); + + ret = 1; + goto done; + } + + else if(restart) + { + /* Check if we have an executable shutdown script */ + if(check_jail_command(name, "/etc/rc")) + run_jail_command(name, "/etc/rc", NULL, JAIL_OUT_CONSOLE); + + goto done; + } + } + + pass++; + + if(!check_running_processes(kd)) + goto done; + } + +done: + if(kd != NULL) + kvm_close(kd); + + return ret; +} + +void kill_jail_processes(kvm_t* kd, int sig) +{ + struct kinfo_proc* kp; + int nentries, i; + pid_t cur; + + cur = getpid(); + + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + + /* Okay now loop and look at each process' jail */ + for(i = 0; i < nentries; i++) + { + if(kp[i].ki_pid == cur) + continue; + + if(kill(kp[i].ki_pid, sig) == -1) + { + if(errno != ESRCH) + errx(1, "couldn't signal process: %d", (int)kp[i].ki_pid); + } + } +} + +int check_running_processes(kvm_t* kd) +{ + struct kinfo_proc* kp; + int nentries, i; + pid_t cur; + + cur = getpid(); + + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + + if(&nentries != 1) + return 1; + + /* Okay now loop and look at each process' jail */ + for(i = 0; i < nentries; i++) + { + if(kp[i].ki_pid != cur) + return 1; + } + + return 0; +} + +static void usage() +{ + fprintf(stderr, "usage: killjail [ -r ] [ -t timeout ] [ -qf ] jailname ...\n"); + exit(2); +} -- cgit v1.2.3