From e11f6612b763e48e70b88290a29e553976e88534 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 19 May 2004 15:41:33 +0000 Subject: Support for running inside a jail --- srcx/jkill.c | 251 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 175 insertions(+), 76 deletions(-) (limited to 'srcx/jkill.c') diff --git a/srcx/jkill.c b/srcx/jkill.c index 79b24bb..d3fdf53 100644 --- a/srcx/jkill.c +++ b/srcx/jkill.c @@ -66,31 +66,178 @@ #define DEFAULT_TIMEOUT 3 int g_timeout = DEFAULT_TIMEOUT; -/* Supress warnings */ -int g_quiet = 0; -int g_verbose = 0; +int g_quiet = 0; /* Supress warnings */ +int g_verbose = 0; /* Print output from scripts */ +int g_force = 0; /* Use SIGKILL after if processes don't exit */ +int g_usescripts = 1; /* Call startup and shutdown scripts */ +int g_restart = 0; /* Restart jail after stop */ +static int kill_jail(const char* jail); static void kill_jail_processes(kvm_t* kd, int sig); -static int kill_jail(const char* jail, int usescripts, int restart, int force); static int check_running_processes(kvm_t* kd); + +static void parse_jail_opts(int argc, char* argv[]); +static void parse_host_opts(int argc, char* argv[]); + static void usage(); +static void usage_jail(const char* name); int main(int argc, char* argv[]) { - int ch, r, jid; + int r, jid; int ret = 0; - int restart = 0; - int force = 0; - int verbose = 0; - int usescripts = 1; pid_t child; + /* + * When running in a jail we do things slightly + * differently, and accept different args + */ + if(running_in_jail()) + { + parse_jail_opts(argc, argv); + + /* + * Turn into a daemon, so that we don't get disconnected + * when we kill our parent program. + */ + if(daemon(0, 1) == -1) + err(1, "couldn't disconnect from console"); + + r = kill_jail(argv[0]); + exit(r); + } + + else + { + parse_host_opts(argc, argv); + + argc -= optind; + argv += optind; + + /* For each jail */ + for(; argc > 0; argc--, argv++) + { + jid = translate_jail_name(argv[0]); + if(jid == -1) + { + warnx("unknown jail host name: %s", argv[0]); + ret = 1; + continue; + } + + /* + * We fork and the child goes into the jail and + * does the dirty work. Unless in debug mode where + * we just do one jail. + */ +#ifdef _DEBUG + switch((child = fork())) + { + /* Error condition */ + case -1: + err(1, "couldn't fork child process"); + break; + + /* The child */ + case 0: +#endif + if(jail_attach(jid) == -1) + err(1, "couldn't attach to jail"); + + r = kill_jail(argv[0]); + exit(r); +#ifdef _DEBUG + break; + + /* The parent */ + default: + if(waitpid(child, &r, 0) == -1) + err(1, "error waiting for child process"); + + if(WEXITSTATUS(r) != 0) + ret = WEXITSTATUS(r); + break; + }; +#endif + + argc--; + argv++; + } + + return ret; + } +} + +static void parse_jail_opts(int argc, char* argv[]) +{ + char* t; + int ch; + + t = strchr(argv[0], '/'); + t = t ? t + 1 : argv[0]; + + if(strcmp(argv[0], "halt")) + { + g_verbose = 1; + g_force = 1; + g_usescripts = 1; + } + + else if(strcmp(argv[0], "reboot")) + { + g_verbose = 1; + g_force = 1; + g_usescripts = 1; + g_reboot = 1; + } + + else + { + /* + * When not named either of the above we fall through + * and process the arguments as usual. + */ + parse_host_opts(argc, argv); + return; + } + + while((ch = getopt(argc, argv, "dk:lnqp")) != -1) + { + switch(ch) + { + case 'd': + case 'k': + case 'l': + case 'n': + case 'q': + case 'p': + warnx("the '-%c' option is not supported from inside a jail", (char)ch); + break; + + case '?': + default: + usage_jail(t); + break; + } + } + + argc -= optind; + argv += optind; + + if(argc > 0) + usage_jail(t); +} + +static void parse_host_opts(int argc, char* argv[]) +{ + int ch; + while((ch = getopt(argc, argv, "fhkqrt:v")) != -1) { switch(ch) { case 'f': - force = 1; + g_force = 1; break; case 'h': @@ -99,7 +246,7 @@ int main(int argc, char* argv[]) break; case 'k': - usescripts = 0; + g_usescripts = 0; break; case 'q': @@ -108,7 +255,7 @@ int main(int argc, char* argv[]) break; case 'r': - restart = 1; + g_restart = 1; break; /* Timeout to use between kills */ @@ -126,72 +273,18 @@ int main(int argc, char* argv[]) case '?': default: usage(); + break; } } - argc -= optind; - argv += optind; - - /* Make sure we have a jail id or name */ - if(argc == 0) + if(!g_usescripts && g_restart) usage(); - if(!usescripts && restart) - usage(); - - if(running_in_jail()) - errx(1, "can't run inside jail"); - - /* For each jail */ - for(; argc > 0; argc--, argv++) - { - jid = translate_jail_name(argv[0]); - if(jid == -1) - { - warnx("unknown jail host name: %s", argv[0]); - ret = 1; - continue; - } - - /* - * We fork and the child goes into the jail and - * does the dirty work. - */ -#ifdef _DEBUG - switch((child = fork())) - { - /* Error condition */ - case -1: - err(1, "couldn't fork child process"); - break; - - /* The child */ - case 0: -#endif - if(jail_attach(jid) == -1) - err(1, "couldn't attach to jail"); - - r = kill_jail(argv[0], usescripts, restart, force); - exit(r); -#ifdef _DEBUG - break; - - /* The parent */ - default: - if(waitpid(child, &r, 0) == -1) - err(1, "error waiting for child process"); - - if(WEXITSTATUS(r) != 0) - ret = WEXITSTATUS(r); - break; - }; -#endif - - argc--; - argv++; - } + argc -= optind; + argv += optind; - return ret; + if(argc <= 0) + usage(); } #define SHUTDOWN_SCRIPT "/etc/rc.shutdown" @@ -200,7 +293,7 @@ static char* SHUTDOWN_ARGS[] = { _PATH_BSHELL, SHUTDOWN_SCRIPT }; #define START_SCRIPT "/etc/rc" static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT }; -static int kill_jail(const char* jail, int usescripts, int restart, int force) +static int kill_jail(const char* jail) { kvm_t* kd = NULL; char errbuf[_POSIX2_LINE_MAX]; @@ -239,7 +332,7 @@ static int kill_jail(const char* jail, int usescripts, int restart, int force) case 0: /* Check if we have an executable shutdown script */ - if(usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) + if(g_usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) run_jail_command(jail, SHUTDOWN_ARGS[0], SHUTDOWN_ARGS, cmdargs); break; @@ -259,7 +352,7 @@ static int kill_jail(const char* jail, int usescripts, int restart, int force) /* Okay now we force kill the processes if necessary */ case 3: - if(force) + if(g_force) { /* If we get here, jailer looks like it's really irresponsive */ if(!g_quiet) @@ -288,7 +381,7 @@ static int kill_jail(const char* jail, int usescripts, int restart, int force) } done: - if(restart) + if(g_restart) { /* Check if we have an executable shutdown script */ if(check_jail_command(jail, START_SCRIPT)) @@ -358,3 +451,9 @@ static void usage() fprintf(stderr, " jkill -r [-fqv] [-t timeout] jail ...\n"); exit(2); } + +static void usage_jail(const char* name) +{ + fprintf(stderr, "usage: %s\n", name); + exit(2); +} -- cgit v1.2.3