summaryrefslogtreecommitdiff
path: root/src/dumm/guest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumm/guest.c')
-rw-r--r--src/dumm/guest.c162
1 files changed, 86 insertions, 76 deletions
diff --git a/src/dumm/guest.c b/src/dumm/guest.c
index bbb59f431..4b2652688 100644
--- a/src/dumm/guest.c
+++ b/src/dumm/guest.c
@@ -41,6 +41,7 @@
#define DIFF_DIR "diff"
#define UNION_DIR "union"
#define MEMORY_FILE "mem"
+#define PID_FILE "pid"
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
#define NOTIFY_FILE "notify"
@@ -63,8 +64,6 @@ struct private_guest_t {
int pid;
/** state of guest */
guest_state_t state;
- /** log file for console 0 */
- int bootlog;
/** FUSE cowfs instance */
cowfs_t *cowfs;
/** mconsole to control running UML */
@@ -94,7 +93,7 @@ static char* get_name(private_guest_t *this)
*/
static iface_t* create_iface(private_guest_t *this, char *name)
{
- iterator_t *iterator;
+ enumerator_t *enumerator;
iface_t *iface;
if (this->state != GUEST_RUNNING)
@@ -103,17 +102,17 @@ static iface_t* create_iface(private_guest_t *this, char *name)
return NULL;
}
- iterator = this->ifaces->create_iterator(this->ifaces, TRUE);
- while (iterator->iterate(iterator, (void**)&iface))
+ enumerator = this->ifaces->create_enumerator(this->ifaces);
+ while (enumerator->enumerate(enumerator, (void**)&iface))
{
if (streq(name, iface->get_guestif(iface)))
{
DBG1("guest '%s' already has an interface '%s'", this->name, name);
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
return NULL;
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
iface = iface_create(this->name, name, this->mconsole);
if (iface)
@@ -124,11 +123,32 @@ static iface_t* create_iface(private_guest_t *this, char *name)
}
/**
- * Implementation of guest_t.create_iface_iterator.
+ * Implementation of guest_t.destroy_iface.
*/
-static iterator_t* create_iface_iterator(private_guest_t *this)
+static void destroy_iface(private_guest_t *this, iface_t *iface)
{
- return this->ifaces->create_iterator(this->ifaces, TRUE);
+ enumerator_t *enumerator;
+ iface_t *current;
+
+ enumerator = this->ifaces->create_enumerator(this->ifaces);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (current == iface)
+ {
+ this->ifaces->remove_at(this->ifaces, enumerator);
+ current->destroy(current);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Implementation of guest_t.create_iface_enumerator.
+ */
+static enumerator_t* create_iface_enumerator(private_guest_t *this)
+{
+ return this->ifaces->create_enumerator(this->ifaces);
}
/**
@@ -170,45 +190,62 @@ static char* write_arg(char **pos, size_t *left, char *format, ...)
}
/**
- * Implementation of get_t.close_console.
+ * Implementation of guest_t.stop.
*/
-static char* get_console(private_guest_t *this, int console)
+static void stop(private_guest_t *this, idle_function_t idle)
{
- if (this->state == GUEST_RUNNING)
+ if (this->state != GUEST_STOPPED)
{
- return this->mconsole->get_console_pts(this->mconsole, console);
+ this->state = GUEST_STOPPING;
+ this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
+ this->ifaces = linked_list_create();
+ kill(this->pid, SIGINT);
+ while (this->state != GUEST_STOPPED)
+ {
+ if (idle)
+ {
+ idle();
+ }
+ else
+ {
+ usleep(50000);
+ }
+ }
+ unlinkat(this->dir, PID_FILE, 0);
}
- return NULL;
}
/**
- * Implementation of guest_t.stop.
+ * save pid in file
*/
-static void stop(private_guest_t *this)
+void savepid(private_guest_t *this)
{
- if (this->state != GUEST_STOPPED)
+ FILE *file;
+
+ file = fdopen(openat(this->dir, PID_FILE, O_RDWR | O_CREAT | O_TRUNC,
+ PERM), "w");
+ if (file)
{
- this->state = GUEST_STOPPING;
- this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
- this->ifaces = linked_list_create();
- kill(this->pid, SIGINT);
- waitpid(this->pid, NULL, 0);
- this->state = GUEST_STOPPED;
+ fprintf(file, "%d", this->pid);
+ fclose(file);
}
}
/**
* Implementation of guest_t.start.
*/
-static bool start(private_guest_t *this)
+static bool start(private_guest_t *this, invoke_function_t invoke, void* data,
+ idle_function_t idle)
{
char buf[2048];
char *notify;
char *pos = buf;
- char *args[16];
+ char *args[32];
int i = 0;
size_t left = sizeof(buf);
+ memset(args, 0, sizeof(args));
+
if (this->state != GUEST_STOPPED)
{
DBG1("unable to start guest in state %N", guest_state_names, this->state);
@@ -226,32 +263,22 @@ static bool start(private_guest_t *this)
args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
args[i++] = write_arg(&pos, &left, "mconsole=notify:%s", notify);
- args[i++] = write_arg(&pos, &left, "con=pts");
- args[i++] = write_arg(&pos, &left, "con0=none,fd:%d", this->bootlog);
- args[i++] = NULL;
+ args[i++] = write_arg(&pos, &left, "con=null");
- this->pid = fork();
- switch (this->pid)
- {
- case 0: /* child, */
- dup2(open("/dev/null", 0), 0);
- dup2(this->bootlog, 1);
- dup2(this->bootlog, 2);
- execvp(args[0], args);
- DBG1("starting UML kernel '%s' failed: %m", args[0]);
- exit(1);
- case -1:
- this->state = GUEST_STOPPED;
- return FALSE;
- default:
- break;
+ this->pid = invoke(data, &this->public, args, i);
+ if (!this->pid)
+ {
+ this->state = GUEST_STOPPED;
+ return FALSE;
}
+ savepid(this);
+
/* open mconsole */
- this->mconsole = mconsole_create(notify);
+ this->mconsole = mconsole_create(notify, idle);
if (this->mconsole == NULL)
{
DBG1("opening mconsole at '%s' failed, stopping guest", buf);
- stop(this);
+ stop(this, NULL);
return FALSE;
}
@@ -266,6 +293,7 @@ static bool load_template(private_guest_t *this, char *path)
{
char dir[PATH_MAX];
size_t len;
+ iface_t *iface;
if (path == NULL)
{
@@ -285,7 +313,15 @@ static bool load_template(private_guest_t *this, char *path)
return FALSE;
}
}
- return this->cowfs->set_overlay(this->cowfs, dir);
+ if (!this->cowfs->set_overlay(this->cowfs, dir))
+ {
+ return FALSE;
+ }
+ while (this->ifaces->remove_last(this->ifaces, (void**)&iface) == SUCCESS)
+ {
+ iface->destroy(iface);
+ }
+ return TRUE;
}
/**
@@ -293,10 +329,6 @@ static bool load_template(private_guest_t *this, char *path)
*/
static void sigchild(private_guest_t *this)
{
- if (this->state != GUEST_STOPPING)
- { /* collect zombie if uml crashed */
- waitpid(this->pid, NULL, WNOHANG);
- }
DESTROY_IF(this->mconsole);
this->mconsole = NULL;
this->state = GUEST_STOPPED;
@@ -341,22 +373,6 @@ static bool mount_unionfs(private_guest_t *this)
}
/**
- * open logfile for boot messages
- */
-static int open_bootlog(private_guest_t *this)
-{
- int fd;
-
- fd = openat(this->dir, LOG_FILE, O_WRONLY | O_CREAT, PERM);
- if (fd == -1)
- {
- DBG1("opening bootlog failed, using stdout");
- return 1;
- }
- return fd;
-}
-
-/**
* load memory configuration from file
*/
int loadmem(private_guest_t *this)
@@ -402,12 +418,8 @@ bool savemem(private_guest_t *this, int mem)
*/
static void destroy(private_guest_t *this)
{
- stop(this);
+ stop(this, NULL);
umount_unionfs(this);
- if (this->bootlog > 1)
- {
- close(this->bootlog);
- }
if (this->dir > 0)
{
close(this->dir);
@@ -430,10 +442,10 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.get_pid = (pid_t(*)(guest_t*))get_pid;
this->public.get_state = (guest_state_t(*)(guest_t*))get_state;
this->public.create_iface = (iface_t*(*)(guest_t*,char*))create_iface;
- this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
+ this->public.destroy_iface = (void(*)(guest_t*,iface_t*))destroy_iface;
+ this->public.create_iface_enumerator = (enumerator_t*(*)(guest_t*))create_iface_enumerator;
this->public.start = (void*)start;
this->public.stop = (void*)stop;
- this->public.get_console = (char*(*)(guest_t*,int))get_console;
this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy;
@@ -458,13 +470,11 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
free(this);
return NULL;
}
-
this->pid = 0;
this->state = GUEST_STOPPED;
this->mconsole = NULL;
this->ifaces = linked_list_create();
this->mem = 0;
- this->bootlog = open_bootlog(this);
this->name = strdup(name);
this->cowfs = NULL;