diff options
-rw-r--r-- | src/dumm/dumm.c | 16 | ||||
-rw-r--r-- | src/dumm/dumm.h | 4 | ||||
-rw-r--r-- | src/dumm/guest.c | 59 | ||||
-rw-r--r-- | src/dumm/guest.h | 42 | ||||
-rw-r--r-- | src/dumm/iface.c | 2 | ||||
-rw-r--r-- | src/dumm/main.c | 210 | ||||
-rw-r--r-- | src/dumm/mconsole.c | 160 | ||||
-rw-r--r-- | src/dumm/mconsole.h | 7 |
8 files changed, 351 insertions, 149 deletions
diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index f5ca7d300..bc690c515 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -26,22 +26,16 @@ struct private_dumm_t { linked_list_t *guests; }; -static guest_t* start_guest(private_dumm_t *this, char *name, char *kernel, - char *master, int mem) +static guest_t* create_guest(private_dumm_t *this, char *name, char *master, int mem) { guest_t *guest; - guest = guest_create(name, kernel, master, mem); + guest = guest_create(name, master, mem); if (guest) { - if (guest->start(guest)) - { - this->guests->insert_last(this->guests, guest); - return guest; - } - guest->destroy(guest); + this->guests->insert_last(this->guests, guest); } - return NULL; + return guest; } static iterator_t* create_guest_iterator(private_dumm_t *this) @@ -73,7 +67,7 @@ dumm_t *dumm_create() { private_dumm_t *this = malloc_thing(private_dumm_t); - this->public.start_guest = (void*)start_guest; + 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 fd2ba46e8..e33d14be5 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.h @@ -39,13 +39,11 @@ struct dumm_t { * @brief Starts a new UML guest * * @param name name of the guest - * @param kernel kernel to boot * @param master mounted read only master filesystem * @param mem amount of memory for guest, in MB * @return guest if started, NULL if failed */ - guest_t* (*start_guest) (dumm_t *this, char *name, char *kernel, - char *master, int mem); + guest_t* (*create_guest) (dumm_t *this, char *name, char *master, int mem); /** * @brief Create an iterator over all guests. diff --git a/src/dumm/guest.c b/src/dumm/guest.c index 32af9333c..dc97c2d57 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -38,14 +38,14 @@ struct private_guest_t { guest_t public; /** name of the guest */ char *name; - /** kernel to boot for guest */ - char *kernel; /** read only master filesystem guest uses */ char *master; /** amount of memory for guest, in MB */ int mem; /** pid of guest child process */ int pid; + /** state of guest */ + guest_state_t state; /** log file for console 0 */ int bootlog; /** mconsole to control running UML */ @@ -54,6 +54,14 @@ struct private_guest_t { linked_list_t *ifaces; }; +ENUM(guest_state_names, GUEST_STOPPED, GUEST_STOPPING, + "STOPPED", + "STARTING", + "RUNNING", + "PAUSED", + "STOPPING", +); + /** * Implementation of guest_t.get_name. */ @@ -103,6 +111,22 @@ static iterator_t* create_iface_iterator(private_guest_t *this) { return this->ifaces->create_iterator(this->ifaces, TRUE); } + +/** + * Implementation of guest_t.get_state. + */ +static guest_state_t get_state(private_guest_t *this) +{ + return this->state; +} + +/** + * Implementation of guest_t.get_pid. + */ +static pid_t get_pid(private_guest_t *this) +{ + return this->pid; +} /** * write format string to a buffer, and advance buffer position @@ -129,16 +153,26 @@ static char* write_arg(char **pos, size_t *left, char *format, ...) /** * Implementation of guest_t.start. */ -static bool start(private_guest_t *this) +static bool start(private_guest_t *this, char *kernel) { char buf[1024]; char cwd[512]; + char *notify; char *pos = buf; char *args[16]; int i = 0; size_t left = sizeof(buf); - - args[i++] = this->kernel; + + if (this->state != GUEST_STOPPED) + { + DBG1("unable to start guest in state %N", guest_state_names, this->state); + return FALSE; + } + this->state = GUEST_STARTING; + + notify = write_arg(&pos, &left, "%s/%s/notify", RUN_DIR, this->name); + + args[i++] = kernel; args[i++] = write_arg(&pos, &left, "root=/dev/root"); args[i++] = write_arg(&pos, &left, "rootfstype=hostfs"); args[i++] = write_arg(&pos, &left, "rootflags=%s/%s/%s", @@ -146,9 +180,11 @@ static bool start(private_guest_t *this) args[i++] = write_arg(&pos, &left, "uml_dir=%s/%s", RUN_DIR, this->name); 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=null,fd:%d", this->bootlog); - args[i++] = write_arg(&pos, &left, "con1=fd:0,fd:1"); + /*args[i++] = write_arg(&pos, &left, "con1=fd:0,fd:1");*/ + args[i++] = write_arg(&pos, &left, "con2=null,null"); args[i++] = write_arg(&pos, &left, "con3=null,null"); args[i++] = write_arg(&pos, &left, "con4=null,null"); args[i++] = write_arg(&pos, &left, "con5=null,null"); @@ -172,8 +208,7 @@ static bool start(private_guest_t *this) break; } /* open mconsole */ - snprintf(buf, sizeof(buf), "%s/%s/%s/mconsole", RUN_DIR, this->name, this->name); - this->mconsole = mconsole_create(buf); + this->mconsole = mconsole_create(notify); if (this->mconsole == NULL) { DBG1("opening mconsole at '%s' failed, stopping guest", buf); @@ -181,6 +216,7 @@ static bool start(private_guest_t *this) this->pid = 0; return FALSE; } + this->state = GUEST_RUNNING; return TRUE; } @@ -293,7 +329,6 @@ static void destroy(private_guest_t *this) this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); DESTROY_IF(this->mconsole); free(this->name); - free(this->kernel); free(this->master); free(this); } @@ -301,11 +336,13 @@ static void destroy(private_guest_t *this) /** * create the guest instance, including required dirs and mounts */ -guest_t *guest_create(char *name, char *kernel, char *master, int mem) +guest_t *guest_create(char *name, char *master, int mem) { private_guest_t *this = malloc_thing(private_guest_t); this->public.get_name = (void*)get_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.start = (void*)start; @@ -320,10 +357,10 @@ guest_t *guest_create(char *name, char *kernel, char *master, int mem) } this->name = strdup(name); - this->kernel = strdup(kernel); this->master = strdup(master); this->mem = mem; this->pid = 0; + this->state = GUEST_STOPPED; this->bootlog = open_bootlog(name); this->mconsole = NULL; this->ifaces = linked_list_create(); diff --git a/src/dumm/guest.h b/src/dumm/guest.h index f4e9f50c6..38aef4b67 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -21,6 +21,29 @@ #include "iface.h" +typedef enum guest_state_t guest_state_t; + +/** + * @brief State of a guest (started, stopped, ...) + */ +enum guest_state_t { + /** guest kernel not running at all */ + GUEST_STOPPED, + /** kernel started, but not yet available */ + GUEST_STARTING, + /** guest is up and running */ + GUEST_RUNNING, + /** guest has been paused */ + GUEST_PAUSED, + /** guest is stopping (shutting down) */ + GUEST_STOPPING, +}; + +/** + * string mappings for guest_state_t + */ +extern enum_name_t *guest_state_names; + typedef struct guest_t guest_t; /** @@ -36,11 +59,25 @@ struct guest_t { char* (*get_name) (guest_t *this); /** + * @brief Get the process ID of the guest child process. + * + * @return name of the guest + */ + pid_t (*get_pid) (guest_t *this); + /** + * @brief Get the state of the guest (stopped, started, etc.). + * + * @return guests state + */ + guest_state_t (*get_state)(guest_t *this); + + /** * @brief Start the guest. * + * @param kernel kernel to boot for this guest * @return TRUE if guest successfully started */ - bool (*start) (guest_t *this); + bool (*start) (guest_t *this, char *kernel); /** * @brief Kill the guest. @@ -74,11 +111,10 @@ struct guest_t { * @brief Create a new, unstarted guest. * * @param name name of the guest - * @param kernel kernel to boot for this guest * @param master read-only master filesystem for guest * @param mem amount of memory to give the guest */ -guest_t *guest_create(char *name, char *kernel, char *master, int mem); +guest_t *guest_create(char *name, char *master, int mem); #endif /* GUEST_H */ diff --git a/src/dumm/iface.c b/src/dumm/iface.c index 56b4322f2..798251c3c 100644 --- a/src/dumm/iface.c +++ b/src/dumm/iface.c @@ -3,7 +3,7 @@ * Hochschule fuer Technik Rapperswil * Copyright (C) 2002 Jeff Dike * - * Based on the "tunctl" utlity from Jeff Dike. + * Based on the "tunctl" utility from Jeff Dike. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/dumm/main.c b/src/dumm/main.c index 437e4ed0e..86fb08ac7 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -39,23 +39,21 @@ static void usage() */ static void help() { - printf("start name=<name> [options] start a guest named <name>\n"); - printf(" additional options:\n"); - printf(" kernel=<uml-kernel>\n"); - printf(" master=<read-only root files>\n"); - printf(" memory=<guest memory in MB>\n"); + printf("create name=<name> start a guest named <name>\n"); + printf(" [master=<dir>] read only master root filesystem\n"); + printf(" [memory=<MB>] guest main memory in megabyte\n"); printf("list list running guests\n"); printf("guest <name> open guest menu for <name>\n"); printf("help show this help\n"); printf("quit kill quests and exit\n"); } - /** * help for guest shell */ static void help_guest() { + printf("start [kernel=<uml-kernel>] start the 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"); @@ -64,83 +62,6 @@ static void help_guest() } /** - * start an UML guest - */ -static void start(dumm_t *dumm, char *line) -{ - enum { - NAME = 0, - MASTER, - KERNEL, - MEMORY, - }; - char *const opts[] = { - [NAME] = "name", - [MASTER] = "master", - [KERNEL] = "kernel", - [MEMORY] = "memory", - NULL - }; - char *value; - char *name = NULL; - char *kernel = NULL; - char *master = NULL; - int mem = 0; - - while (TRUE) - { - switch (getsubopt(&line, opts, &value)) - { - case NAME: - name = value; - continue; - case MASTER: - master = value; - continue; - case KERNEL: - kernel = value; - continue; - case MEMORY: - if (value) - { - mem = atoi(value); - } - continue; - default: - break; - } - break; - } - if (name == NULL) - { - printf("option 'name' is required.\n"); - help(); - return; - } - if (kernel == NULL) - { - kernel = "./linux"; - } - if (master == NULL) - { - master = "master"; - } - if (mem == 0) - { - mem = 128; - } - - if (dumm->start_guest(dumm, name, kernel, master, mem)) - { - printf("starting guest '%s'\n", name); - } - else - { - printf("starting guest '%s' failed\n", name); - } -} - -/** * add an iface to a guest */ static void add_if(guest_t *guest, char *name) @@ -208,6 +129,49 @@ static void list_if(guest_t *guest) } /** + * start an UML guest + */ +static void start_guest(guest_t *guest, char *line) +{ + enum { + KERNEL = 0, + }; + char *const opts[] = { + [KERNEL] = "kernel", + NULL + }; + char *value; + char *kernel = NULL; + + while (TRUE) + { + switch (getsubopt(&line, opts, &value)) + { + case KERNEL: + kernel = value; + continue; + default: + break; + } + break; + } + if (kernel == NULL) + { + kernel = "./linux"; + } + + printf("starting guest '%s'... \n", guest->get_name(guest)); + if (guest->start(guest, kernel)) + { + printf("guest '%s' is up\n", guest->get_name(guest)); + } + else + { + printf("failed to start guest '%s'!\n", guest->get_name(guest)); + } +} + +/** * subshell for guests */ static void guest(dumm_t *dumm, char *name) @@ -246,6 +210,7 @@ static void guest(dumm_t *dumm, char *name) enum { QUIT = 0, HELP, + START, ADDIF, DELIF, LISTIF, @@ -253,6 +218,7 @@ static void guest(dumm_t *dumm, char *name) char *const opts[] = { [QUIT] = "quit", [HELP] = "help", + [START] = "start", [ADDIF] = "addif", [DELIF] = "delif", [LISTIF] = "listif", @@ -285,6 +251,9 @@ static void guest(dumm_t *dumm, char *name) case HELP: help_guest(); continue; + case START: + start_guest(guest, pos); + continue; case ADDIF: add_if(guest, pos); continue; @@ -303,6 +272,73 @@ static void guest(dumm_t *dumm, char *name) } /** + * create an UML guest + */ +static void create_guest(dumm_t *dumm, char *line) +{ + enum { + NAME = 0, + MASTER, + MEMORY, + }; + char *const opts[] = { + [NAME] = "name", + [MASTER] = "master", + [MEMORY] = "memory", + NULL + }; + char *value; + char *name = NULL; + char *master = NULL; + int mem = 0; + + while (TRUE) + { + switch (getsubopt(&line, opts, &value)) + { + case NAME: + name = value; + continue; + case MASTER: + master = value; + continue; + case MEMORY: + if (value) + { + mem = atoi(value); + } + continue; + default: + break; + } + break; + } + if (name == NULL) + { + printf("option 'name' is required.\n"); + help(); + return; + } + if (master == NULL) + { + master = "master"; + } + if (mem == 0) + { + mem = 128; + } + if (dumm->create_guest(dumm, name, master, mem)) + { + printf("guest '%s' created\n", name); + guest(dumm, name); + } + else + { + printf("failed to create guest '%s'!\n", name); + } +} + +/** * list running UML guests */ static void list(dumm_t *dumm) @@ -370,14 +406,14 @@ int main(int argc, char *argv[]) enum { QUIT = 0, HELP, - START, + CREATE, LIST, GUEST, }; char *const opts[] = { [QUIT] = "quit", [HELP] = "help", - [START] = "start", + [CREATE] = "create", [LIST] = "list", [GUEST] = "guest", NULL @@ -410,8 +446,8 @@ int main(int argc, char *argv[]) case HELP: help(); continue; - case START: - start(dumm, pos); + case CREATE: + create_guest(dumm, pos); continue; case LIST: list(dumm); diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c index 466a68ad9..32c969bac 100644 --- a/src/dumm/mconsole.c +++ b/src/dumm/mconsole.c @@ -3,7 +3,7 @@ * Hochschule fuer Technik Rapperswil * Copyright (C) 2001-2004 Jeff Dike * - * Based on the "uml_mconsole" utilty from Jeff Dike. + * Based on the "uml_mconsole" utility from Jeff Dike. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -36,28 +36,57 @@ struct private_mconsole_t { /** public interface */ mconsole_t public; /** mconsole socket */ - int socket; + int console; + /** notify socket */ + int notify; /** address of uml socket */ struct sockaddr_un uml; }; /** + * mconsole message format from "arch/um/include/mconsole.h" + */ +typedef struct mconsole_request mconsole_request; +/** mconsole request message */ +struct mconsole_request { + u_int32_t magic; + u_int32_t version; + u_int32_t len; + char data[MCONSOLE_MAX_DATA]; +}; + + +typedef struct mconsole_reply mconsole_reply; +/** mconsole reply message */ +struct mconsole_reply { + u_int32_t err; + u_int32_t more; + u_int32_t len; + char data[MCONSOLE_MAX_DATA]; +}; + +typedef struct mconsole_notify mconsole_notify; +/** mconsole notify message */ +struct mconsole_notify { + u_int32_t magic; + u_int32_t version; + enum { + MCONSOLE_SOCKET, + MCONSOLE_PANIC, + MCONSOLE_HANG, + MCONSOLE_USER_NOTIFY, + } type; + u_int32_t len; + char data[MCONSOLE_MAX_DATA]; +}; + +/** * send a request to UML using mconsole */ static bool request(private_mconsole_t *this, char *command) { - struct { - u_int32_t magic; - u_int32_t version; - u_int32_t len; - char data[MCONSOLE_MAX_DATA]; - } request; - struct { - u_int32_t err; - u_int32_t more; - u_int32_t len; - char data[MCONSOLE_MAX_DATA]; - } reply; + mconsole_request request; + mconsole_reply reply; bool first = TRUE, good = TRUE; int len; @@ -67,7 +96,7 @@ static bool request(private_mconsole_t *this, char *command) request.len = min(strlen(command), sizeof(reply.data) - 1); strncpy(request.data, command, request.len); - if (sendto(this->socket, &request, sizeof(request), 0, + if (sendto(this->console, &request, sizeof(request), 0, (struct sockaddr*)&this->uml, sizeof(this->uml)) < 0) { DBG1("sending mconsole command to UML failed: %m"); @@ -75,7 +104,7 @@ static bool request(private_mconsole_t *this, char *command) } do { - len = recvfrom(this->socket, &reply, sizeof(reply), 0, NULL, 0); + len = recvfrom(this->console, &reply, sizeof(reply), 0, NULL, 0); if (len < 0) { DBG1("receiving from mconsole failed: %m"); @@ -129,41 +158,110 @@ static bool del_iface(private_mconsole_t *this, char *guest) */ static void destroy(private_mconsole_t *this) { - close(this->socket); + close(this->console); + close(this->notify); free(this); } /** - * create the mconsole instance + * setup the mconsole notify connection and wait for its readyness */ -mconsole_t *mconsole_create(char *sock) +static bool wait_for_notify(private_mconsole_t *this, char *nsock) { struct sockaddr_un addr; + mconsole_notify notify; + int len; + + this->notify = socket(AF_UNIX, SOCK_DGRAM, 0); + if (this->notify < 0) + { + DBG1("opening mconsole notify socket failed: %m"); + return FALSE; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, nsock, sizeof(addr)); + if (bind(this->notify, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1("binding mconsole notify socket to '%s' failed: %m", nsock); + close(this->notify); + return FALSE; + } + len = recvfrom(this->notify, ¬ify, sizeof(notify), 0, NULL, 0); + if (len < 0 || len >= sizeof(notify)) + { + DBG1("reading from mconsole notify socket failed: %m"); + close(this->notify); + unlink(nsock); + return FALSE; + } + if (notify.magic != MCONSOLE_MAGIC || + notify.version != MCONSOLE_VERSION || + notify.type != MCONSOLE_SOCKET) + { + DBG1("received unexpected message from mconsole notify socket: %b", + ¬ify, sizeof(notify)); + close(this->notify); + unlink(nsock); + return FALSE; + } + memset(&this->uml, 0, sizeof(this->uml)); + this->uml.sun_family = AF_UNIX; + strncpy(this->uml.sun_path, (char*)¬ify.data, sizeof(this->uml.sun_path)); + return TRUE; +} + +/** + * setup the mconsole console connection + */ +static bool setup_console(private_mconsole_t *this) +{ + struct sockaddr_un addr; + + this->console = socket(AF_UNIX, SOCK_DGRAM, 0); + if (this->console < 0) + { + DBG1("opening mconsole socket failed: %m"); + return FALSE; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(&addr.sun_path[1], sizeof(addr.sun_path), "%5d-%d", + getpid(), this->console); + if (bind(this->console, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1("binding mconsole socket to '%s' failed: %m", &addr.sun_path[1]); + close(this->console); + return FALSE; + } + return TRUE; +} + +/** + * create the mconsole instance + */ +mconsole_t *mconsole_create(char *notify) +{ private_mconsole_t *this = malloc_thing(private_mconsole_t); this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface; this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface; this->public.destroy = (void*)destroy; - this->socket = socket(AF_UNIX, SOCK_DGRAM, 0); - if (this->socket < 0) + if (!wait_for_notify(this, notify)) { - DBG1("opening mconsole socket failed: %m"); free(this); return NULL; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(&addr.sun_path[1], sizeof(addr.sun_path), "%5d-%s", getpid(), sock); - if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) + + if (!setup_console(this)) { - DBG1("binding mconsole socket failed: %m"); - destroy(this); + close(this->notify); + unlink(notify); + free(this); return NULL; } - memset(&this->uml, 0, sizeof(this->uml)); - this->uml.sun_family = AF_UNIX; - strncpy(this->uml.sun_path, sock, sizeof(this->uml.sun_path)); + unlink(notify); return &this->public; } diff --git a/src/dumm/mconsole.h b/src/dumm/mconsole.h index 8d71053a5..cf4f69957 100644 --- a/src/dumm/mconsole.h +++ b/src/dumm/mconsole.h @@ -51,10 +51,13 @@ struct mconsole_t { /** * @brief Create a new mconsole connection to a guest. * - * @param socket guests mconsole socket + * Waits for a notification from the guest through the notify socket and tries + * to connect to the mconsole socket supplied in the received notification. + * + * @param notify unix notify socket path * @return mconsole instance, or NULL if failed */ -mconsole_t *mconsole_create(char *socket); +mconsole_t *mconsole_create(char *notify); #endif /* MCONSOLE_H */ |