usable without scenarios

This commit is contained in:
Martin Willi
2007-08-08 12:35:24 +00:00
parent 3dcf9dbd70
commit 7b7201bee6
10 changed files with 589 additions and 335 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c main.c dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c main.c
gcc -o dumm dumm.c guest.c iface.c bridge.c mconsole.c cowfs.c main.c `pkg-config fuse --cflags --libs` -lreadline -lbridge -lpthread -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing gcc -o dumm dumm.c guest.c iface.c bridge.c mconsole.c cowfs.c main.c `pkg-config fuse --cflags --libs` -ledit -lbridge -lpthread -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing
+17 -6
View File
@@ -49,9 +49,9 @@ static iterator_t* create_iface_iterator(private_bridge_t *this)
} }
/** /**
* Implementation of bridge_t.del_iface. * Implementation of bridge_t.disconnect_iface.
*/ */
static bool del_iface(private_bridge_t *this, iface_t *iface) static bool disconnect_iface(private_bridge_t *this, iface_t *iface)
{ {
iterator_t *iterator; iterator_t *iterator;
iface_t *current; iface_t *current;
@@ -69,6 +69,7 @@ static bool del_iface(private_bridge_t *this, iface_t *iface)
} }
else else
{ {
iface->set_bridge(iface, NULL);
good = TRUE; good = TRUE;
} }
break; break;
@@ -84,9 +85,9 @@ static bool del_iface(private_bridge_t *this, iface_t *iface)
} }
/** /**
* Implementation of bridge_t.add_iface. * Implementation of bridge_t.connect_iface.
*/ */
static bool add_iface(private_bridge_t *this, iface_t *iface) static bool connect_iface(private_bridge_t *this, iface_t *iface)
{ {
if (br_add_interface(this->name, iface->get_hostif(iface)) != 0) if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
{ {
@@ -94,6 +95,7 @@ static bool add_iface(private_bridge_t *this, iface_t *iface)
iface->get_hostif(iface), this->name); iface->get_hostif(iface), this->name);
return FALSE; return FALSE;
} }
iface->set_bridge(iface, &this->public);
this->ifaces->insert_last(this->ifaces, iface); this->ifaces->insert_last(this->ifaces, iface);
return TRUE; return TRUE;
} }
@@ -103,11 +105,20 @@ static bool add_iface(private_bridge_t *this, iface_t *iface)
*/ */
static int instances = 0; static int instances = 0;
/**
* unregister an interface from bridge
*/
static void unregister(iface_t *iface)
{
iface->set_bridge(iface, NULL);
}
/** /**
* Implementation of bridge_t.destroy. * Implementation of bridge_t.destroy.
*/ */
static void destroy(private_bridge_t *this) static void destroy(private_bridge_t *this)
{ {
this->ifaces->invoke_function(this->ifaces, (void(*)(void*))unregister);
this->ifaces->destroy(this->ifaces); this->ifaces->destroy(this->ifaces);
if (br_del_bridge(this->name) != 0) if (br_del_bridge(this->name) != 0)
{ {
@@ -140,8 +151,8 @@ bridge_t *bridge_create(char *name)
this = malloc_thing(private_bridge_t); this = malloc_thing(private_bridge_t);
this->public.get_name = (char*(*)(bridge_t*))get_name; this->public.get_name = (char*(*)(bridge_t*))get_name;
this->public.create_iface_iterator = (iterator_t*(*)(bridge_t*))create_iface_iterator; this->public.create_iface_iterator = (iterator_t*(*)(bridge_t*))create_iface_iterator;
this->public.del_iface = (bool(*)(bridge_t*, iface_t *iface))del_iface; this->public.disconnect_iface = (bool(*)(bridge_t*, iface_t *iface))disconnect_iface;
this->public.add_iface = (bool(*)(bridge_t*, iface_t *iface))add_iface; this->public.connect_iface = (bool(*)(bridge_t*, iface_t *iface))connect_iface;
this->public.destroy = (void*)destroy; this->public.destroy = (void*)destroy;
if (br_add_bridge(name) != 0) if (br_add_bridge(name) != 0)
+5 -5
View File
@@ -19,10 +19,10 @@
#include <library.h> #include <library.h>
#include <utils/iterator.h> #include <utils/iterator.h>
#include "iface.h"
typedef struct bridge_t bridge_t; typedef struct bridge_t bridge_t;
#include "iface.h"
/** /**
* @brief Interface in a guest, connected to a tap device on the host. * @brief Interface in a guest, connected to a tap device on the host.
*/ */
@@ -41,15 +41,15 @@ struct bridge_t {
* @param iface interface to add * @param iface interface to add
* @return TRUE if interface added * @return TRUE if interface added
*/ */
bool (*add_iface)(bridge_t *this, iface_t *iface); bool (*connect_iface)(bridge_t *this, iface_t *iface);
/** /**
* @brief Remove an interface from a bridge. * @brief Remove an interface from a bridge.
* *
* @param iface interface to remove * @param iface interface to remove
* @return TRUE ifinterface removed * @return TRUE if interface removed
*/ */
bool (*del_iface)(bridge_t *this, iface_t *iface); bool (*disconnect_iface)(bridge_t *this, iface_t *iface);
/** /**
* @brief Create an iterator over all interfaces. * @brief Create an iterator over all interfaces.
+106 -3
View File
@@ -16,14 +16,21 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <debug.h> #include <debug.h>
#include "dumm.h" #include "dumm.h"
#define PERME (S_IRWXU | S_IRWXG)
#define GUEST_DIR "guests"
#define SCENARIO_DIR "scenarios"
#define SCENARIO_DIFF_DIR "diff"
/** /**
* instances of dumm, used to deliver signals * instances of dumm, used to deliver signals
*/ */
@@ -36,6 +43,12 @@ struct private_dumm_t {
dumm_t public; dumm_t public;
/** working dir */ /** working dir */
char *dir; char *dir;
/** directory of guests */
char *guest_dir;
/** directory of scenarios */
char *scenario_dir;
/** directory of loaded scenario */
char *scenario;
/** list of managed guests */ /** list of managed guests */
linked_list_t *guests; linked_list_t *guests;
/** list of managed bridges */ /** list of managed bridges */
@@ -52,7 +65,7 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
{ {
guest_t *guest; guest_t *guest;
guest = guest_create(this->dir, name, kernel, master, mem); guest = guest_create(this->guest_dir, name, kernel, master, mem);
if (guest) if (guest)
{ {
this->guests->insert_last(this->guests, guest); this->guests->insert_last(this->guests, guest);
@@ -91,6 +104,80 @@ static iterator_t* create_bridge_iterator(private_dumm_t *this)
return this->bridges->create_iterator(this->bridges, TRUE); return this->bridges->create_iterator(this->bridges, TRUE);
} }
static void clear_scenario(private_dumm_t *this)
{
iterator_t *iterator;
guest_t *guest;
free(this->scenario);
this->scenario = NULL;
iterator = this->guests->create_iterator(this->guests, TRUE);
while (iterator->iterate(iterator, (void**)&guest))
{
guest->set_scenario(guest, NULL);
}
iterator->destroy(iterator);
}
/**
* Implementation of dumm_t.load_scenario.
*/
static bool load_scenario(private_dumm_t *this, char *name)
{
iterator_t *iterator;
guest_t *guest;
char dir[PATH_MAX];
size_t len;
free(this->scenario);
asprintf(&this->scenario, "%s/%s", this->scenario_dir, name);
if (access(this->scenario, F_OK) == 0)
{ /* exists, load scenario */
DBG1("scenario loading unimplemented.");
return FALSE;
}
else
{ /* does not exist, create scenario */
if (mkdir(this->scenario, PERME) != 0)
{
DBG1("creating scenario directory '%s' failed: %m", this->scenario);
clear_scenario(this);
return FALSE;
}
len = snprintf(dir, sizeof(dir), "%s/%s/%s", this->scenario,
SCENARIO_DIR, SCENARIO_DIFF_DIR);
if (len < 0 || len >= sizeof(dir))
{
clear_scenario(this);
return FALSE;
}
iterator = this->guests->create_iterator(this->guests, TRUE);
while (iterator->iterate(iterator, (void**)&guest))
{
if (!guest->set_scenario(guest, dir))
{
iterator->destroy(iterator);
clear_scenario(this);
return FALSE;
}
}
iterator->destroy(iterator);
}
return TRUE;
}
/**
* Implementation of dumm_t.save_scenario.
*/
static bool save_scenario(private_dumm_t *this)
{
DBG1("scenario loading unimplemented.");
return FALSE;
}
/** /**
* signal handler * signal handler
*/ */
@@ -205,6 +292,9 @@ static void destroy(private_dumm_t *this)
this->destroying = TRUE; this->destroying = TRUE;
this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy)); this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
free(this->guest_dir);
free(this->scenario_dir);
free(this->scenario);
free(this->dir); free(this->dir);
remove_instance(this); remove_instance(this);
free(this); free(this);
@@ -219,7 +309,7 @@ static void load_guests(private_dumm_t *this)
struct dirent *ent; struct dirent *ent;
guest_t *guest; guest_t *guest;
dir = opendir(this->dir); dir = opendir(this->guest_dir);
if (dir == NULL) if (dir == NULL)
{ {
return; return;
@@ -231,9 +321,10 @@ static void load_guests(private_dumm_t *this)
{ {
continue; continue;
} }
guest = guest_load(this->dir, ent->d_name); guest = guest_load(this->guest_dir, ent->d_name);
if (guest) if (guest)
{ {
DBG1("loaded guest '%s'", ent->d_name);
this->guests->insert_last(this->guests, guest); this->guests->insert_last(this->guests, guest);
} }
else else
@@ -256,6 +347,8 @@ dumm_t *dumm_create(char *dir)
this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator; this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator;
this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge; this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator; this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator;
this->public.load_scenario = (bool(*)(dumm_t*, char *name))load_scenario;
this->public.save_scenario = (bool(*)(dumm_t*))save_scenario;
this->public.destroy = (void(*)(dumm_t*))destroy; this->public.destroy = (void(*)(dumm_t*))destroy;
this->destroying = FALSE; this->destroying = FALSE;
@@ -267,11 +360,21 @@ dumm_t *dumm_create(char *dir)
{ {
asprintf(&this->dir, "%s/%s", cwd, dir); asprintf(&this->dir, "%s/%s", cwd, dir);
} }
this->scenario = NULL;
asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
asprintf(&this->scenario_dir, "%s/%s", this->dir, SCENARIO_DIR);
this->guests = linked_list_create(); this->guests = linked_list_create();
this->bridges = linked_list_create(); this->bridges = linked_list_create();
add_instance(this); add_instance(this);
if (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST)
{
DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
destroy(this);
return NULL;
}
load_guests(this); load_guests(this);
return &this->public; return &this->public;
} }
+15
View File
@@ -69,6 +69,21 @@ struct dumm_t {
*/ */
iterator_t* (*create_bridge_iterator)(dumm_t *this); iterator_t* (*create_bridge_iterator)(dumm_t *this);
/**
* @brief Loads a scenario, create a new one if it does not exist.
*
* @param name name of the scenario to load/create
* @return FALSE if load/crate failed
*/
bool (*load_scenario)(dumm_t *this, char *name);
/**
* @brief Saves the current loaded scenario.
*
* @return FALSE if saving scenario failed
*/
bool (*save_scenario)(dumm_t *this);
/** /**
* @brief stop all guests and destroy the modeler * @brief stop all guests and destroy the modeler
*/ */
+35 -1
View File
@@ -36,6 +36,14 @@
#define PERME (S_IRWXU | S_IRWXG) #define PERME (S_IRWXU | S_IRWXG)
#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define MASTER_DIR "master"
#define DIFF_DIR "diff"
#define UNION_DIR "union"
#define MEMORY_FILE "mem"
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
#define NOTIFY_FILE "notify"
typedef struct private_guest_t private_guest_t; typedef struct private_guest_t private_guest_t;
struct private_guest_t { struct private_guest_t {
@@ -178,7 +186,7 @@ static void stop(private_guest_t *this)
/** /**
* Implementation of guest_t.start. * Implementation of guest_t.start.
*/ */
static bool start(private_guest_t *this, char *kernel) static bool start(private_guest_t *this)
{ {
char buf[2048]; char buf[2048];
char *notify; char *notify;
@@ -243,6 +251,31 @@ static bool start(private_guest_t *this, char *kernel)
return TRUE; return TRUE;
} }
/**
* Implementation of guest_t.set_scenario.
*/
static bool set_scenario(private_guest_t *this, char *path)
{
char dir[PATH_MAX];
size_t len;
len = snprintf(dir, sizeof(dir), "%s/%s", path, this->name);
if (len < 0 || len >= sizeof(dir))
{
return FALSE;
}
if (access(dir, F_OK) != 0)
{
if (mkdir(dir, PERME) != 0)
{
DBG1("creating scenario overlay for guest '%s' failed: %m", this->name);
return FALSE;
}
}
this->cowfs->set_scenario(this->cowfs, dir);
return TRUE;
}
/** /**
* Implementation of guest_t.sigchild. * Implementation of guest_t.sigchild.
*/ */
@@ -388,6 +421,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator; this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
this->public.start = (void*)start; this->public.start = (void*)start;
this->public.stop = (void*)stop; this->public.stop = (void*)stop;
this->public.set_scenario = (bool(*)(guest_t*, char *path))set_scenario;
this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy; this->public.destroy = (void*)destroy;
+12 -12
View File
@@ -21,14 +21,6 @@
#include "iface.h" #include "iface.h"
#define MASTER_DIR "master"
#define DIFF_DIR "diff"
#define UNION_DIR "union"
#define MEMORY_FILE "mem"
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
#define NOTIFY_FILE "notify"
typedef enum guest_state_t guest_state_t; typedef enum guest_state_t guest_state_t;
/** /**
@@ -72,6 +64,7 @@ struct guest_t {
* @return name of the guest * @return name of the guest
*/ */
pid_t (*get_pid) (guest_t *this); pid_t (*get_pid) (guest_t *this);
/** /**
* @brief Get the state of the guest (stopped, started, etc.). * @brief Get the state of the guest (stopped, started, etc.).
* *
@@ -82,10 +75,9 @@ struct guest_t {
/** /**
* @brief Start the guest. * @brief Start the guest.
* *
* @param kernel kernel to boot for this guest
* @return TRUE if guest successfully started * @return TRUE if guest successfully started
*/ */
bool (*start) (guest_t *this, char *kernel); bool (*start) (guest_t *this);
/** /**
* @brief Kill the guest. * @brief Kill the guest.
@@ -95,7 +87,7 @@ struct guest_t {
bool (*stop) (guest_t *this); bool (*stop) (guest_t *this);
/** /**
* @brief Create a new interface for that host. * @brief Create a new interface in the current scenario.
* *
* @param name name of the interface in the guest * @param name name of the interface in the guest
* @return created interface, or NULL if failed * @return created interface, or NULL if failed
@@ -110,7 +102,15 @@ struct guest_t {
iterator_t* (*create_iface_iterator)(guest_t *this); iterator_t* (*create_iface_iterator)(guest_t *this);
/** /**
* @brief Called whenever a SIGCHILD is received. * @brief Set the scenario COWFS overlay to use.
*
* @param parent parent directory where scenario diff should point to
* @return FALSE if failed
*/
bool (*set_scenario)(guest_t *this, char *parent);
/**
* @brief Called whenever a SIGCHILD for the guests PID is received.
*/ */
void (*sigchild)(guest_t *this); void (*sigchild)(guest_t *this);
+16
View File
@@ -37,6 +37,8 @@ struct private_iface_t {
char *guestif; char *guestif;
/** device name at host (tap0) */ /** device name at host (tap0) */
char *hostif; char *hostif;
/** bridge this interface is attached to */
bridge_t *bridge;
/** mconsole for guest */ /** mconsole for guest */
mconsole_t *mconsole; mconsole_t *mconsole;
}; };
@@ -57,6 +59,14 @@ static char* get_hostif(private_iface_t *this)
return this->hostif; return this->hostif;
} }
/**
* Implementation of iface_t.set_bridge.
*/
static void set_bridge(private_iface_t *this, bridge_t *bridge)
{
this->bridge = bridge;
}
/** /**
* destroy the tap device * destroy the tap device
*/ */
@@ -121,6 +131,10 @@ static char* create_tap(private_iface_t *this, char *guest)
*/ */
static void destroy(private_iface_t *this) static void destroy(private_iface_t *this)
{ {
if (this->bridge)
{
this->bridge->disconnect_iface(this->bridge, &this->public);
}
this->mconsole->del_iface(this->mconsole, this->guestif); this->mconsole->del_iface(this->mconsole, this->guestif);
destroy_tap(this); destroy_tap(this);
free(this->guestif); free(this->guestif);
@@ -137,11 +151,13 @@ iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole)
this->public.get_hostif = (char*(*)(iface_t*))get_hostif; this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
this->public.get_guestif = (char*(*)(iface_t*))get_guestif; this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
this->public.destroy = (void*)destroy; this->public.destroy = (void*)destroy;
this->mconsole = mconsole; this->mconsole = mconsole;
this->guestif = strdup(guestif); this->guestif = strdup(guestif);
this->hostif = create_tap(this, guest); this->hostif = create_tap(this, guest);
this->bridge = NULL;
if (this->hostif == NULL) if (this->hostif == NULL)
{ {
destroy_tap(this); destroy_tap(this);
+13 -5
View File
@@ -19,12 +19,13 @@
#include <library.h> #include <library.h>
#include <utils/iterator.h> #include <utils/iterator.h>
#include "mconsole.h"
#define TAP_DEVICE "/dev/net/tun" #define TAP_DEVICE "/dev/net/tun"
typedef struct iface_t iface_t; typedef struct iface_t iface_t;
#include "mconsole.h"
#include "bridge.h"
/** /**
* @brief Interface in a guest, connected to a tap device on the host. * @brief Interface in a guest, connected to a tap device on the host.
*/ */
@@ -33,22 +34,28 @@ struct iface_t {
/** /**
* @brief Get the interface name in the guest (e.g. eth0). * @brief Get the interface name in the guest (e.g. eth0).
* *
* @return guest interface name * @return guest interface name
*/ */
char* (*get_guestif)(iface_t *this); char* (*get_guestif)(iface_t *this);
/** /**
* @brief Get the interface name at the host (e.g. tap0). * @brief Get the interface name at the host (e.g. tap0).
* *
* @return host interface (tap device) name * @return host interface (tap device) name
*/ */
char* (*get_hostif)(iface_t *this); char* (*get_hostif)(iface_t *this);
/**
* @brief Set the bridge this interface is attached to.
*
* @param bridge assigned bridge, or NULL for none
*/
void (*set_bridge)(iface_t *this, bridge_t *bridge);
/* /*
bool (*up) (iface_t *this); bool (*up) (iface_t *this);
bool (*down) (iface_t *this); bool (*down) (iface_t *this);
bool (*add_addr) (iface_t *this, host_t *addr); bool (*add_addr) (iface_t *this, host_t *addr);
bool (*del_addr) (iface_t *this, host_t *addr);
iterator_t* (*create_addr_iterator) (iface_t *this); iterator_t* (*create_addr_iterator) (iface_t *this);
*/ */
@@ -69,3 +76,4 @@ struct iface_t {
iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole); iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole);
#endif /* IFACE_H */ #endif /* IFACE_H */
+368 -301
View File
@@ -39,34 +39,7 @@ static void usage()
printf(" --help|-h show this help\n"); printf(" --help|-h show this help\n");
} }
/** #if 0
* help for dumm root shell
*/
static void help()
{
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 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");
printf("help show this help\n");
printf("quit quit the guest menu\n");
}
/** /**
* add an iface to a guest * add an iface to a guest
*/ */
@@ -133,248 +106,86 @@ static void list_if(guest_t *guest)
} }
iterator->destroy(iterator); iterator->destroy(iterator);
} }
#endif
/** /**
* start an UML guest * readline() wrapper
*/ */
static void start_guest(guest_t *guest, char *line) static char* get_line(char *format, ...)
{ {
enum { char *line = NULL;
KERNEL = 0, char *prompt = "";
}; va_list args;
char *const opts[] = {
[KERNEL] = "kernel", va_start(args, format);
NULL vasprintf(&prompt, format, args);
}; va_end(args);
char *value;
char *kernel = NULL;
while (TRUE) while (TRUE)
{ {
switch (getsubopt(&line, opts, &value)) line = readline(prompt);
if (line == NULL)
{ {
case KERNEL: continue;
kernel = value;
continue;
default:
break;
} }
if (*line == '\0')
{
free(line);
continue;
}
add_history(line);
break; break;
} }
if (kernel == NULL) free(prompt);
{ return line;
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));
}
} }
/** /**
* stop (kill) an UML guest * get a guest by name
*/ */
static void stop_guest(guest_t *guest, char *line) static guest_t* get_guest(char *name)
{ {
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(char *name)
{
char *line = NULL;
char prompt[32];
int len;
iterator_t *iterator; iterator_t *iterator;
guest_t *guest; guest_t *guest = NULL;
bool found = FALSE;
iterator = dumm->create_guest_iterator(dumm); iterator = dumm->create_guest_iterator(dumm);
while (iterator->iterate(iterator, (void**)&guest)) while (iterator->iterate(iterator, (void**)&guest))
{ {
if (streq(name, guest->get_name(guest))) if (streq(guest->get_name(guest), name))
{ {
found = TRUE;
break; break;
} }
guest = NULL;
} }
iterator->destroy(iterator); iterator->destroy(iterator);
if (!found) return guest;
{
printf("guest '%s' not found\n", name);
return;
}
len = snprintf(prompt, sizeof(prompt), "dumm@%s# ", name);
if (len < 0 || len >= sizeof(prompt))
{
return;
}
while (TRUE)
{
enum {
QUIT = 0,
HELP,
START,
STOP,
ADDIF,
DELIF,
LISTIF,
};
char *const opts[] = {
[QUIT] = "quit",
[HELP] = "help",
[START] = "start",
[STOP] = "stop",
[ADDIF] = "addif",
[DELIF] = "delif",
[LISTIF] = "listif",
NULL
};
char *pos, *value;
free(line);
line = readline(prompt);
if (line == NULL || *line == '\0')
{
continue;
}
add_history(line);
pos = line;
while (*pos != '\0')
{
if (*pos == ' ')
{
*pos = ',';
}
pos++;
}
pos = line;
switch (getsubopt(&pos, opts, &value))
{
case QUIT:
free(line);
break;
case HELP:
help_guest();
continue;
case START:
start_guest(guest, pos);
continue;
case STOP:
stop_guest(guest, pos);
continue;
case ADDIF:
add_if(guest, pos);
continue;
case DELIF:
del_if(guest, pos);
continue;
case LISTIF:
list_if(guest);
continue;
default:
printf("command unknown: '%s'\n", line);
continue;
}
break;
}
} }
/** /**
* create an bridge * get a bridge by name
*/ */
static void create_bridge(char *name) static bridge_t* get_bridge(char *name)
{ {
dumm->create_bridge(dumm, name); iterator_t *iterator;
bridge_t *bridge = NULL;
} iterator = dumm->create_bridge_iterator(dumm);
while (iterator->iterate(iterator, (void**)&bridge))
/**
* create an UML guest
*/
static void create_guest(char *line)
{
enum {
NAME = 0,
KERNEL,
MASTER,
MEMORY,
};
char *const opts[] = {
[NAME] = "name",
[KERNEL] = "kernel",
[MASTER] = "master",
[MEMORY] = "memory",
NULL
};
char *value;
char *name = NULL;
char *master = NULL;
char *kernel = NULL;
int mem = 128;
while (TRUE)
{ {
switch (getsubopt(&line, opts, &value)) if (streq(bridge->get_name(bridge), name))
{ {
case NAME: break;
name = value;
continue;
case KERNEL:
kernel = value;
continue;
case MASTER:
master = value;
continue;
case MEMORY:
if (value)
{
mem = atoi(value);
}
continue;
default:
break;
} }
break; bridge = NULL;
}
if (name == NULL || master == NULL || kernel == NULL)
{
printf("too few arguments!\n");
help();
return;
}
if (mem == 0)
{
mem = 128;
}
if (dumm->create_guest(dumm, name, kernel, master, mem))
{
printf("guest '%s' created\n", name);
guest(name);
}
else
{
printf("failed to create guest '%s'!\n", name);
} }
iterator->destroy(iterator);
return bridge;
} }
/** /**
* list running UML guests * get an interface by guest name
*/ */
static void list() static iface_t* get_iface(char *name, char *ifname)
{ {
iterator_t *guests, *ifaces; iterator_t *guests, *ifaces;
guest_t *guest; guest_t *guest;
@@ -383,17 +194,315 @@ static void list()
guests = dumm->create_guest_iterator(dumm); guests = dumm->create_guest_iterator(dumm);
while (guests->iterate(guests, (void**)&guest)) while (guests->iterate(guests, (void**)&guest))
{ {
printf("%s (%N)\n", guest->get_name(guest), if (streq(guest->get_name(guest), name))
guest_state_names, guest->get_state(guest));
ifaces = guest->create_iface_iterator(guest);
while (ifaces->iterate(ifaces, (void**)&iface))
{ {
printf(" '%s' => '%s'\n", iface = NULL;
iface->get_guestif(iface), iface->get_hostif(iface)); ifaces = guest->create_iface_iterator(guest);
while (ifaces->iterate(ifaces, (void**)&iface))
{
if (streq(iface->get_guestif(iface), ifname))
{
break;
}
iface = NULL;
}
ifaces->destroy(ifaces);
if (iface)
{
break;
}
} }
ifaces->destroy(ifaces);
} }
guests->destroy(guests); guests->destroy(guests);
return iface;
}
static void guest_addif_menu(guest_t *guest)
{
char *name;
name = get_line("interface name: ");
if (!guest->create_iface(guest, name))
{
printf("creating interface failed\n");
}
}
static void guest_delif_menu(guest_t *guest)
{
char *name;
iface_t *iface;
iterator_t *iterator;
bool found = FALSE;
name = get_line("interface name: ");
iterator = guest->create_iface_iterator(guest);
while (iterator->iterate(iterator, (void**)&iface))
{
if (streq(iface->get_guestif(iface), name))
{
iterator->remove(iterator);
iface->destroy(iface);
found = TRUE;
break;
}
}
iterator->destroy(iterator);
if (!found)
{
printf("interface '%s' not found\n");
}
}
static void guest_menu(guest_t *guest)
{
while (TRUE)
{
char *line = get_line("guest/%s# ", guest->get_name(guest));
if (streq(line, "back"))
{
free(line);
break;
}
else if (streq(line, "start"))
{
if (guest->start(guest))
{
printf("guest '%s' is booting\n", guest->get_name(guest));
}
else
{
printf("failed to start guest '%s'\n", guest->get_name(guest));
}
}
else if (streq(line, "stop"))
{
printf("stopping guest '%s'...\n", guest->get_name(guest));
guest->stop(guest);
printf("guest '%s' is down\n", guest->get_name(guest));
}
else if (streq(line, "addif"))
{
guest_addif_menu(guest);
}
else if (streq(line, "delif"))
{
guest_delif_menu(guest);
}
else
{
printf("back|start|stop|addif|delif\n");
}
free(line);
}
}
static void guest_create_menu()
{
char *name, *kernel, *master, *mem;
guest_t *guest;
name = get_line("guest name: ");
kernel = get_line("kernel image: ");
master = get_line("master filesystem: ");
mem = get_line("amount of memory in MB: ");
guest = dumm->create_guest(dumm, name, kernel, master, atoi(mem));
if (guest)
{
printf("guest '%s' created\n", guest->get_name(guest));
guest_menu(guest);
}
else
{
printf("failed to create guest '%s'\n", name);
}
}
static void guest_list_menu()
{
while (TRUE)
{
iterator_t *iterator;
guest_t *guest;
char *line = get_line("guest# ");
if (streq(line, "back"))
{
free(line);
break;
}
else if (streq(line, "list"))
{
iterator = dumm->create_guest_iterator(dumm);
while (iterator->iterate(iterator, (void**)&guest))
{
printf("%s\n", guest->get_name(guest));
}
iterator->destroy(iterator);
}
else if (streq(line, "create"))
{
guest_create_menu();
}
else
{
guest = get_guest(line);
if (guest)
{
guest_menu(guest);
}
else
{
printf("back|list|create|<guest>\n");
}
}
free(line);
}
}
static void bridge_addif_menu(bridge_t *bridge)
{
char *name, *ifname;
iface_t *iface;
name = get_line("guest name: ");
ifname = get_line("interface name: ");
iface = get_iface(name, ifname);
if (!iface)
{
printf("guest '%s' has no interface named '%s'\n", name, ifname);
}
else if (!bridge->connect_iface(bridge, iface))
{
printf("failed to add interface '%s' to bridge '%s'\n", ifname,
bridge->get_name(bridge));
}
}
static void bridge_delif_menu(bridge_t *bridge)
{
char *name, *ifname;
iface_t *iface;
name = get_line("guest name: ");
ifname = get_line("interface name: ");
iface = get_iface(name, ifname);
if (!iface)
{
printf("guest '%s' has no interface named '%s'\n", name, ifname);
}
else if (!bridge->disconnect_iface(bridge, iface))
{
printf("failed to remove interface '%s' from bridge '%s'\n", ifname,
bridge->get_name(bridge));
}
}
static void bridge_menu(bridge_t *bridge)
{
while (TRUE)
{
char *line = get_line("bridge/%s# ", bridge->get_name(bridge));
if (streq(line, "back"))
{
free(line);
break;
}
else if (streq(line, "list"))
{
iterator_t *iterator;
iface_t *iface;
iterator = bridge->create_iface_iterator(bridge);
while (iterator->iterate(iterator, (void**)&iface))
{
printf("%s (%s)\n", iface->get_guestif(iface), iface->get_hostif(iface));
}
iterator->destroy(iterator);
}
else if (streq(line, "addif"))
{
bridge_addif_menu(bridge);
}
else if (streq(line, "delif"))
{
bridge_delif_menu(bridge);
}
else
{
printf("back|list|addif|delif\n");
}
free(line);
}
}
static void bridge_create_menu()
{
char *name;
bridge_t *bridge;
name = get_line("bridge name: ");
bridge = dumm->create_bridge(dumm, name);
if (bridge)
{
printf("bridge '%s' created\n", bridge->get_name(bridge));
bridge_menu(bridge);
}
else
{
printf("failed to create bridge '%s'\n", name);
}
}
static void bridge_list_menu()
{
while (TRUE)
{
iterator_t *iterator;
bridge_t *bridge;
char *line = get_line("bridge# ");
if (streq(line, "back"))
{
free(line);
break;
}
else if (streq(line, "list"))
{
iterator = dumm->create_bridge_iterator(dumm);
while (iterator->iterate(iterator, (void**)&bridge))
{
printf("%s\n", bridge->get_name(bridge));
}
iterator->destroy(iterator);
}
else if (streq(line, "create"))
{
bridge_create_menu();
}
else
{
bridge = get_bridge(line);
if (bridge)
{
bridge_menu(bridge);
}
else
{
printf("back|list|create|<bridge>\n");
}
}
free(line);
}
} }
/** /**
@@ -401,7 +510,9 @@ static void list()
*/ */
void signal_action(int sig, siginfo_t *info, void *ucontext) void signal_action(int sig, siginfo_t *info, void *ucontext)
{ {
printf("\nuse 'quit'\ndumm# "); dumm->destroy(dumm);
clear_history();
exit(0);
} }
/** /**
@@ -409,7 +520,6 @@ void signal_action(int sig, siginfo_t *info, void *ucontext)
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *line = NULL;
struct sigaction action; struct sigaction action;
char *dir = "."; char *dir = ".";
@@ -438,8 +548,6 @@ int main(int argc, char *argv[])
break; break;
} }
dumm = dumm_create(dir);
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_action; action.sa_sigaction = signal_action;
action.sa_flags = SA_SIGINFO; action.sa_flags = SA_SIGINFO;
@@ -451,70 +559,29 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
dumm = dumm_create(dir);
while (TRUE) while (TRUE)
{ {
enum { char *line = get_line("# ");
QUIT = 0,
HELP,
CREATE,
BRIDGE,
LIST,
GUEST,
};
char *const opts[] = {
[QUIT] = "quit",
[HELP] = "help",
[CREATE] = "create",
[BRIDGE] = "bridge",
[LIST] = "list",
[GUEST] = "guest",
NULL
};
char *pos, *value;
if (streq(line, "quit"))
{
free(line);
break;
}
else if (streq(line, "guest"))
{
guest_list_menu();
}
else if (streq(line, "bridge"))
{
bridge_list_menu();
}
else
{
printf("quit|guest|bridge\n");
}
free(line); free(line);
line = readline("dumm# ");
if (line == NULL || *line == '\0')
{
continue;
}
add_history(line);
pos = line;
while (*pos != '\0')
{
if (*pos == ' ')
{
*pos = ',';
}
pos++;
}
pos = line;
switch (getsubopt(&pos, opts, &value))
{
case QUIT:
free(line);
break;
case HELP:
help();
continue;
case CREATE:
create_guest(pos);
continue;
case BRIDGE:
create_bridge(pos);
continue;
case LIST:
list();
continue;
case GUEST:
guest(pos);
continue;
default:
printf("command unknown: '%s'\n", line);
continue;
}
break;
} }
dumm->destroy(dumm); dumm->destroy(dumm);
clear_history(); clear_history();