fixed scenario loading
[strongswan.git] / src / dumm / guest.c
index 533599b..bbb59f4 100644 (file)
@@ -24,6 +24,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <dirent.h>
+#include <termios.h>
 
 #include <debug.h>
 #include <utils/linked_list.h>
 #include "dumm.h"
 #include "guest.h"
 #include "mconsole.h"
+#include "cowfs.h"
 
 #define PERME (S_IRWXU | S_IRWXG)
 #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"
+#define PTYS 0
+
 typedef struct private_guest_t private_guest_t;
 
 struct private_guest_t {
@@ -54,8 +65,8 @@ struct private_guest_t {
        guest_state_t state;
        /** log file for console 0 */
        int bootlog;
-       /** has the unionfs been mounted */
-       bool mounted;
+       /** FUSE cowfs instance */
+       cowfs_t *cowfs;
        /** mconsole to control running UML */
        mconsole_t *mconsole;
        /** list of interfaces attached to the guest */
@@ -159,6 +170,18 @@ static char* write_arg(char **pos, size_t *left, char *format, ...)
 }
 
 /**
+ * Implementation of get_t.close_console.
+ */
+static char* get_console(private_guest_t *this, int console)
+{
+       if (this->state == GUEST_RUNNING)
+       {
+               return this->mconsole->get_console_pts(this->mconsole, console);
+       }
+       return NULL;
+}
+
+/**
  * Implementation of guest_t.stop.
  */
 static void stop(private_guest_t *this)
@@ -169,17 +192,15 @@ static void stop(private_guest_t *this)
                this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
                this->ifaces = linked_list_create();
                kill(this->pid, SIGINT);
-               while (this->state == GUEST_STOPPING)
-               {
-                       sched_yield();
-               }
+               waitpid(this->pid, NULL, 0);
+               this->state = GUEST_STOPPED;
        }
 }
 
 /**
  * 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 *notify;
@@ -205,14 +226,8 @@ static bool start(private_guest_t *this, char *kernel)
        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, "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");
-       args[i++] = write_arg(&pos, &left, "con6=null,null");
+       args[i++] = write_arg(&pos, &left, "con=pts");
+       args[i++] = write_arg(&pos, &left, "con0=none,fd:%d", this->bootlog);
        args[i++] = NULL;
          
        this->pid = fork();
@@ -220,8 +235,8 @@ static bool start(private_guest_t *this, char *kernel)
        {
                case 0: /* child,  */
                        dup2(open("/dev/null", 0), 0);
-                       dup2(open("/dev/null", 0), 1);
-                       dup2(open("/dev/null", 0), 2);
+                       dup2(this->bootlog, 1);
+                       dup2(this->bootlog, 2);
                        execvp(args[0], args);
                        DBG1("starting UML kernel '%s' failed: %m", args[0]);
                        exit(1);
@@ -239,8 +254,38 @@ static bool start(private_guest_t *this, char *kernel)
                stop(this);
                return FALSE;
        }
+       
        this->state = GUEST_RUNNING;
        return TRUE;
+}      
+       
+/**
+ * Implementation of guest_t.load_template.
+ */
+static bool load_template(private_guest_t *this, char *path)
+{
+       char dir[PATH_MAX];
+       size_t len;
+       
+       if (path == NULL)
+       {
+               return this->cowfs->set_overlay(this->cowfs, NULL);     
+       }
+       
+       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 overlay for guest '%s' failed: %m", this->name);
+                       return FALSE;
+               }
+       }
+       return this->cowfs->set_overlay(this->cowfs, dir);
 }
 
 /**
@@ -248,7 +293,10 @@ static bool start(private_guest_t *this, char *kernel)
  */
 static void sigchild(private_guest_t *this)
 {
-       waitpid(this->pid, NULL, WNOHANG);
+       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;
@@ -259,21 +307,13 @@ static void sigchild(private_guest_t *this)
  */
 static bool umount_unionfs(private_guest_t *this)
 {
-       char cmd[128];
-       size_t len;
-       
-       if (this->mounted)
+       if (this->cowfs)
        {
-               len = snprintf(cmd, sizeof(cmd), "fusermount -u %s/%s",
-                                          this->dirname, UNION_DIR);
-               if (len < 0 || len >= sizeof(cmd) || system(cmd) != 0)
-               {
-                       DBG1("unmounting guest unionfs failed");
-                       return FALSE;
-               }
-               this->mounted = FALSE;
+               this->cowfs->destroy(this->cowfs);
+               this->cowfs = NULL;
+               return TRUE;
        }
-       return TRUE;
+       return FALSE;
 }
 
 /**
@@ -281,22 +321,23 @@ static bool umount_unionfs(private_guest_t *this)
  */
 static bool mount_unionfs(private_guest_t *this)
 {
-       char cmd[256];
-       size_t len;
-       
-       if (!this->mounted)
+       char master[PATH_MAX];
+       char diff[PATH_MAX];
+       char mount[PATH_MAX];
+
+       if (this->cowfs == NULL)
        {
-               len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s/%s %s/%s",
-                                          this->dirname, MASTER_DIR, this->dirname, DIFF_DIR,
-                                          this->dirname, UNION_DIR);
-               if (len < 0 || len >= sizeof(cmd) || system(cmd) != 0)
+               snprintf(master, sizeof(master), "%s/%s", this->dirname, MASTER_DIR);
+               snprintf(diff, sizeof(diff), "%s/%s", this->dirname, DIFF_DIR);
+               snprintf(mount, sizeof(mount), "%s/%s", this->dirname, UNION_DIR);
+               
+               this->cowfs = cowfs_create(master, diff, mount);
+               if (this->cowfs)
                {
-                       DBG1("mounting guest unionfs failed");
-                       return FALSE;
+                       return TRUE;
                }
-               this->mounted = TRUE;
        }
-       return TRUE;
+       return FALSE;
 }
 
 /**
@@ -392,9 +433,11 @@ 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.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;
-       
+               
        if (*parent == '/' || getcwd(cwd, sizeof(cwd)) == NULL)
        {
                asprintf(&this->dirname, "%s/%s", parent, name);
@@ -423,7 +466,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
        this->mem = 0;
        this->bootlog = open_bootlog(this);
        this->name = strdup(name);
-       this->mounted = FALSE;
+       this->cowfs = NULL;
        
        return this;
 }