implemented mconsole notification to check if guest came up

slightly modified menu commands
This commit is contained in:
Martin Willi
2007-07-26 13:21:06 +00:00
parent 369a17c218
commit 5b608fd7ca
8 changed files with 351 additions and 149 deletions
+5 -11
View File
@@ -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;
+1 -3
View File
@@ -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.
+48 -11
View File
@@ -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();
+39 -3
View File
@@ -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;
/**
@@ -35,12 +58,26 @@ 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 */
+1 -1
View File
@@ -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
+123 -87
View File
@@ -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");
@@ -63,83 +61,6 @@ static void help_guest()
printf("quit quit the guest menu\n");
}
/**
* 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
*/
@@ -207,6 +128,49 @@ static void list_if(guest_t *guest)
iterator->destroy(iterator);
}
/**
* 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
*/
@@ -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;
@@ -302,6 +271,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
*/
@@ -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);
+129 -31
View File
@@ -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);
}
/**
* setup the mconsole notify connection and wait for its readyness
*/
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, &notify, 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",
&notify, 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*)&notify.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 *sock)
mconsole_t *mconsole_create(char *notify)
{
struct sockaddr_un addr;
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;
}
+5 -2
View File
@@ -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 */