diff options
Diffstat (limited to 'src/dumm/guest.c')
-rw-r--r-- | src/dumm/guest.c | 162 |
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**)¤t)) + { + 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; |