aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2007-07-27 07:37:15 +0000
committerMartin Willi <martin@strongswan.org>2007-07-27 07:37:15 +0000
commit539a55a44189e57694e65cf75f5e1040a7fdd37d (patch)
treebfaf9a24855c65090500ba89fd4f4322cd8d62e4
parent5b608fd7cac56eec62e69836fc01886f101b7f85 (diff)
downloadstrongswan-539a55a44189e57694e65cf75f5e1040a7fdd37d.tar.bz2
strongswan-539a55a44189e57694e65cf75f5e1040a7fdd37d.tar.xz
support for killing guests properly
-rw-r--r--src/dumm/Makefile2
-rw-r--r--src/dumm/dumm.c33
-rw-r--r--src/dumm/dumm.h14
-rw-r--r--src/dumm/guest.c23
-rw-r--r--src/dumm/guest.h7
-rw-r--r--src/dumm/main.c72
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);