diff options
author | Martin Willi <martin@strongswan.org> | 2007-07-27 07:37:15 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-07-27 07:37:15 +0000 |
commit | 539a55a44189e57694e65cf75f5e1040a7fdd37d (patch) | |
tree | bfaf9a24855c65090500ba89fd4f4322cd8d62e4 | |
parent | 5b608fd7cac56eec62e69836fc01886f101b7f85 (diff) | |
download | strongswan-539a55a44189e57694e65cf75f5e1040a7fdd37d.tar.bz2 strongswan-539a55a44189e57694e65cf75f5e1040a7fdd37d.tar.xz |
support for killing guests properly
-rw-r--r-- | src/dumm/Makefile | 2 | ||||
-rw-r--r-- | src/dumm/dumm.c | 33 | ||||
-rw-r--r-- | src/dumm/dumm.h | 14 | ||||
-rw-r--r-- | src/dumm/guest.c | 23 | ||||
-rw-r--r-- | src/dumm/guest.h | 7 | ||||
-rw-r--r-- | src/dumm/main.c | 72 |
6 files changed, 135 insertions, 16 deletions
diff --git a/src/dumm/Makefile b/src/dumm/Makefile index c60e57dbc..62aa92913 100644 --- a/src/dumm/Makefile +++ b/src/dumm/Makefile @@ -1,3 +1,3 @@ dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h mconsole.c mconsole.h main.c - gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -Wall + gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index bc690c515..b8f0e0f2c 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -41,6 +41,38 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *master, int static iterator_t* create_guest_iterator(private_dumm_t *this) { return this->guests->create_iterator(this->guests, TRUE); +} + +/** + * Implementation of dumm_t.sigchild_handler. + */ +static void sigchild_handler(private_dumm_t *this, siginfo_t *info) +{ + switch (info->si_code) + { + case CLD_EXITED: + case CLD_KILLED: + case CLD_DUMPED: + case CLD_STOPPED: + { + iterator_t *iterator; + guest_t *guest; + + iterator = this->guests->create_iterator(this->guests, TRUE); + while (iterator->iterate(iterator, (void**)&guest)) + { + if (guest->get_pid(guest) == info->si_pid) + { + guest->sigchild(guest); + break; + } + } + iterator->destroy(iterator); + break; + } + default: + break; + } } static void destroy(private_dumm_t *this) @@ -67,6 +99,7 @@ dumm_t *dumm_create() { private_dumm_t *this = malloc_thing(private_dumm_t); + this->public.sigchild_handler = (void(*)(dumm_t*, siginfo_t *info))sigchild_handler; this->public.create_guest = (void*)create_guest; this->public.create_guest_iterator = (void*)create_guest_iterator; this->public.destroy = (void*)destroy; diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h index e33d14be5..fe4f9ca4e 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.h @@ -16,6 +16,8 @@ #ifndef DUMM_H #define DUMM_H +#include <signal.h> + #include <library.h> #include <utils/linked_list.h> @@ -53,6 +55,18 @@ struct dumm_t { iterator_t* (*create_guest_iterator) (dumm_t *this); /** + * @brief Handler for received SIG_CHILD signals. + * + * Dumm spans children, UML kernels. To track and cleanup these kernel + * processes, it is required that this method is called whenever a SIG_CHILD + * is received. The user is responsible to call sigchild_handler on each + * dumm_t instance with the signals siginfo_t. + * + * @param info siginfo associated to the SIG_CHILD signal + */ + void (*sigchild_handler)(dumm_t *this, siginfo_t *info); + + /** * @brief stop all guests and destroy the modeler */ void (*destroy) (dumm_t *this); diff --git a/src/dumm/guest.c b/src/dumm/guest.c index dc97c2d57..59e501478 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -78,7 +78,7 @@ static iface_t* create_iface(private_guest_t *this, char *name) iterator_t *iterator; iface_t *iface; - if (this->pid == 0) + if (this->state != GUEST_RUNNING) { DBG1("guest '%s' not running, unable to add interface", this->name); return NULL; @@ -225,14 +225,29 @@ static bool start(private_guest_t *this, char *kernel) */ static void stop(private_guest_t *this) { - if (this->pid) + if (this->state != GUEST_STOPPED) { + this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); + this->ifaces = linked_list_create(); kill(this->pid, SIGINT); - this->pid = 0; + this->state = GUEST_STOPPING; + while (this->state == GUEST_STOPPING) + { + sched_yield(); + } } } /** + * Implementation of guest_t.sigchild. + */ +static void sigchild(private_guest_t *this) +{ + this->state = GUEST_STOPPED; + this->pid = 0; +} + +/** * Check if directory exists, create otherwise */ static bool makedir(char *dir, char *name) @@ -326,7 +341,6 @@ static void destroy(private_guest_t *this) { stop(this); umount_unionfs(this->name); - this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); DESTROY_IF(this->mconsole); free(this->name); free(this->master); @@ -347,6 +361,7 @@ guest_t *guest_create(char *name, char *master, int mem) this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator; this->public.start = (void*)start; this->public.stop = (void*)stop; + this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.destroy = (void*)destroy; if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) || diff --git a/src/dumm/guest.h b/src/dumm/guest.h index 38aef4b67..48cfbf240 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -100,7 +100,12 @@ struct guest_t { * @return iterator over iface_t's */ iterator_t* (*create_iface_iterator)(guest_t *this); - + + /** + * @brief Called whenever a SIGCHILD is received. + */ + void (*sigchild)(guest_t *this); + /** * @brief Close and destroy a guest with all interfaces */ diff --git a/src/dumm/main.c b/src/dumm/main.c index 86fb08ac7..e4fc6602a 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -25,6 +25,11 @@ #include "dumm.h" /** + * global set of UMLs guests + */ +dumm_t *dumm; + +/** * show usage information (program arguments) */ static void usage() @@ -53,7 +58,8 @@ static void help() */ static void help_guest() { - printf("start [kernel=<uml-kernel>] start the guest\n"); + printf("start [kernel=<uml-kernel>] start a stopped guest\n"); + printf("stop stop a started guest\n"); printf("addif <name> add an interface to the guest\n"); printf("delif <name> remove the interface\n"); printf("listif list guests interfaces\n"); @@ -172,9 +178,19 @@ static void start_guest(guest_t *guest, char *line) } /** + * stop (kill) an UML guest + */ +static void stop_guest(guest_t *guest, char *line) +{ + printf("stopping guest '%s'...\n", guest->get_name(guest)); + guest->stop(guest); + printf("guest '%s' is down\n", guest->get_name(guest)); +} + +/** * subshell for guests */ -static void guest(dumm_t *dumm, char *name) +static void guest(char *name) { char *line = NULL; char prompt[32]; @@ -211,6 +227,7 @@ static void guest(dumm_t *dumm, char *name) QUIT = 0, HELP, START, + STOP, ADDIF, DELIF, LISTIF, @@ -219,6 +236,7 @@ static void guest(dumm_t *dumm, char *name) [QUIT] = "quit", [HELP] = "help", [START] = "start", + [STOP] = "stop", [ADDIF] = "addif", [DELIF] = "delif", [LISTIF] = "listif", @@ -254,6 +272,9 @@ static void guest(dumm_t *dumm, char *name) case START: start_guest(guest, pos); continue; + case STOP: + stop_guest(guest, pos); + continue; case ADDIF: add_if(guest, pos); continue; @@ -274,7 +295,7 @@ static void guest(dumm_t *dumm, char *name) /** * create an UML guest */ -static void create_guest(dumm_t *dumm, char *line) +static void create_guest(char *line) { enum { NAME = 0, @@ -330,7 +351,7 @@ static void create_guest(dumm_t *dumm, char *line) if (dumm->create_guest(dumm, name, master, mem)) { printf("guest '%s' created\n", name); - guest(dumm, name); + guest(name); } else { @@ -341,7 +362,7 @@ static void create_guest(dumm_t *dumm, char *line) /** * list running UML guests */ -static void list(dumm_t *dumm) +static void list() { iterator_t *guests, *ifaces; guest_t *guest; @@ -350,7 +371,8 @@ static void list(dumm_t *dumm) guests = dumm->create_guest_iterator(dumm); while (guests->iterate(guests, (void**)&guest)) { - printf("%s\n", guest->get_name(guest)); + printf("%s (%N)\n", guest->get_name(guest), + guest_state_names, guest->get_state(guest)); ifaces = guest->create_iface_iterator(guest); while (ifaces->iterate(ifaces, (void**)&iface)) { @@ -363,12 +385,30 @@ static void list(dumm_t *dumm) } /** + * Signal handler + */ +void signal_action(int sig, siginfo_t *info, void *ucontext) +{ + if (sig == SIGCHLD) + { + dumm->sigchild_handler(dumm, info); + } + else + { + dumm->destroy(dumm); + clear_history(); + printf("\n"); + exit(0); + } +} + +/** * main routine, parses args and reads from console */ int main(int argc, char *argv[]) { - dumm_t *dumm; char *line = NULL; + struct sigaction action; while (TRUE) { @@ -400,6 +440,18 @@ int main(int argc, char *argv[]) } dumm = dumm_create(); + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = signal_action; + action.sa_flags = SA_SIGINFO; + if (sigaction(SIGCHLD, &action, NULL) != 0 || + sigaction(SIGINT, &action, NULL) != 0 || + sigaction(SIGQUIT, &action, NULL) != 0 || + sigaction(SIGTERM, &action, NULL) != 0) + { + printf("signal handler setup failed: %m.\n"); + return 1; + } while (TRUE) { @@ -447,13 +499,13 @@ int main(int argc, char *argv[]) help(); continue; case CREATE: - create_guest(dumm, pos); + create_guest(pos); continue; case LIST: - list(dumm); + list(); continue; case GUEST: - guest(dumm, pos); + guest(pos); continue; default: printf("command unknown: '%s'\n", line); |