[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [Libvir] [PATCH 1/2] lxc: start container



Jim -

Thanks!  I was confused for a little while because I know I had deleted that
commented out code.  Looks like I grabbed the patch from the wrong directory.
It's functionally the same but missing some of the cleanup like deleting
commented out code (oops).  Sorry about the confusion.

Most of your comments were still applicable.  I've addressed them inline below
and attached an updated patch.

Thanks again!

Jim Meyering wrote:
> Dave Leskovec <dlesko linux vnet ibm com> wrote:
>> This is a repost of the start container support.  Changes from the last version:
> ...
> 
> Hi Dave,
> 
> Mostly-impeccable code, as usual.
> Here are a few suggestions and questions:
> 
>> Index: b/src/lxc_driver.c
>> ===================================================================
> ...
>> +static int lxcStartContainer(virConnectPtr conn,
>> +                             lxc_driver_t* driver,
>> +                             lxc_vm_t *vm)
>> +{
>> +    int rc = -1;
>> +    int flags;
>> +    int stacksize = getpagesize() * 4;
> 
> I haven't looked at much code using clone, so maybe using
> 4*getpagesize() is just a standard idiom, but I'll comment anyhow.
> 
> Four pages is small, in any case, but I'm curious...
> Do you really always need 4?
> Even when page size is say, 64K?
> I.e., is "4" a heuristic, or can you describe how it was derived?
> Or, if say 32KB is an upper bound, maybe something like this:
> 
>   int stacksize = MIN (getpagesize() * 4, 32 * 1024);

That value is an estimate based on running some containers.  My tests so far
have been fairly simplistic and I'm sure mileage will vary as containers are
utilized.  A few options for improving this:
- allow the user to specify this in the container definition within the os
block (or elsewhere).  This would facilitate upping the size if an overrun is
encountered.
- even if we do this, we still should provide a good default value.  Could set
this default value based on the architecture.
- use mprotect to have a SIGSEGV generated if the stack is overrun

>
...
>> +static int lxcTtyForward(int fd1, int fd2,
>> +                         int *loopFlag ATTRIBUTE_UNUSED,
>> +                         int pollmsecs ATTRIBUTE_UNUSED)
>> +{
> ...
>> +        for (i = 0; i < numFds; ++i) {
>> +            if (!fds[i].revents) {
>> +                continue;
>> +            }
>> +
>> +            if (fds[i].revents & POLLIN) {
>> +                saferead(fds[i].fd, buf, 1);
>> +                if (1 < numFds) {
>> +                    safewrite(fds[i ^ 1].fd, buf, 1);
>> +                }
> 
> Don't you want to handle saferead/safewrite failure?

Yes, added some handling here.

> 
...
>> +    /* fork process to handle the tty io forwarding */
>> +    if ((vm->pid = fork()) == 0) {
>> +        /* child process calls forward routine */
>> +        lxcTtyForward(vm->parentTty, vm->containerTtyFd, NULL, 0);
>> +    }
> 
> Handling/reporting fork failure would be good.

Yes, added some handling.

> 
...
>>  static int lxcStartup(void)
>>  {
>>      uid_t uid = getuid();
>>
>> +    debugFlag = 1;
> 
> Is this a debugging relic?

Yep, removed.

> 
> ...
>> Index: b/src/lxc_container.c
>> ===================================================================
> ...
>> +/* Functions */
>> +static int lxcExecContainerInit(lxc_vm_def_t *vmDef)
> 
> Please make the pointer "const":
> 
>   static int lxcExecContainerInit(const lxc_vm_def_t *vmDef)

Done.

> 
>> +{
>> +    int rc = -1;
>> +    char* execString;
>> +    int execStringLen = strlen(vmDef->init) + 1 + 5;
> 
> s/int/size_t/

Done.

> 
>> +
>> +    if(NULL == (execString = calloc(execStringLen, sizeof(char)))) {
> 
> s/if/if /

Done.

> 
>> +        DEBUG0("failed to calloc memory for init string");
> 
> Memory allocation failure usually deserves an unconditional diagnostic.
> Any reason not to do that here?

I was thinking that I didn't want to call __virRaiseError from within the
container.  If it's just writing to stderr then that shouldn't be a problem.
I've changed many of these but there may be a few more running around.  I'll get
them as I find em.

> 
>> +        goto error_out;
>> +    }
>> +
>> +    strcpy(execString, "exec ");
>> +    strcat(execString, vmDef->init);
>> +
>> +    execl("/bin/sh", "sh", "-c", execString, (char*)NULL);
>> +    DEBUG("execl failed: %s", strerror(errno));
> 
> Same here, and in several cases below?

Right

> 
> ...
>> +#if 0
> 
> This function is 99% identical to the non-'#if-0'd one above.
> Remove it?

Yes, removed

> 
>> +static int lxcTtyForward(int fd1, int fd2, int *loopFlag, int pollmsecs)
>> +{
> ...
>> +}
>> +
>> +static pid_t initPid;
>> +static int exitChildLoop;
>> +static void lxcExecChildHandler(int sig ATTRIBUTE_UNUSED,
>> +                                siginfo_t *signalInfo,
> 
> This pointer can be const:
>                                    const siginfo_t *signalInfo,

This was all removed

> 
...
>> +
>> +    exitChildLoop = 0;
>> +    if ((initPid = fork()) == 0) {
> 
> Check for fork failure here, too.

This was removed.

> 
>> +        if(lxcSetContainerStdio(ttyslave) < 0) {
>> +            exitChildLoop = 1;
>> +            goto exit_with_error;
>> +        }
>> +
>> +        lxcExecContainerInit(vmDef);
>> +        /* this function will not return.  if it fails, it will exit */
>> +    }
>> +
>> +    close(ttyslave);
> 
> Probably no big deal here, but in general,
> it's good practice to report close failure on any writable handle.

Removed - I'll check other uses of close.

> 
>> +    lxcTtyForward(ttymaster, vm->parentTty,
>> +                  &exitChildLoop, 100);
>> +
>> +    DEBUG("child waiting on pid %d", initPid);
>> +    waitpid(initPid, &childStatus, 0);
> 
> It's worthwhile to check for waitpid failure, or perhaps to retry on EINTR.
> I know this is if-0'd, too, but why include it, if not for review?

Removed - I'll check other uses of waitpid.

...

-- 
Best Regards,
Dave Leskovec
IBM Linux Technology Center
Open Virtualization


---
 src/Makefile.am     |    1 
 src/lxc_conf.c      |    1 
 src/lxc_conf.h      |    2 
 src/lxc_container.c |  229 +++++++++++++++++++++++++++
 src/lxc_container.h |   44 +++++
 src/lxc_driver.c    |  431 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 706 insertions(+), 2 deletions(-)

Index: b/src/Makefile.am
===================================================================
--- a/src/Makefile.am	2008-04-07 23:22:25.000000000 -0700
+++ b/src/Makefile.am	2008-04-07 23:22:33.000000000 -0700
@@ -61,6 +61,7 @@
 		openvz_driver.c openvz_driver.h			\
 		lxc_driver.c lxc_driver.h			\
 		lxc_conf.c lxc_conf.h				\
+		lxc_container.c lxc_container.h				\
                 nodeinfo.h nodeinfo.c                           \
 		storage_conf.h storage_conf.c			\
 		storage_driver.h storage_driver.c		\
Index: b/src/lxc_conf.h
===================================================================
--- a/src/lxc_conf.h	2008-04-07 23:22:25.000000000 -0700
+++ b/src/lxc_conf.h	2008-04-08 13:29:51.000000000 -0700
@@ -72,6 +72,8 @@
     char configFileBase[PATH_MAX];
 
     int parentTty;
+    int containerTtyFd;
+    char *containerTty;
 
     lxc_vm_def_t *def;
 
Index: b/src/lxc_container.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/src/lxc_container.c	2008-04-09 16:59:02.000000000 -0700
@@ -0,0 +1,229 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * lxc_container.c: file description
+ *
+ * Authors:
+ *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef WITH_LXC
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "lxc_container.h"
+#include "lxc_conf.h"
+#include "util.h"
+
+#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
+#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
+
+/**
+ * lxcExecContainerInit:
+ * @vmDef: Ptr to vm definition structure
+ *
+ * Exec the container init string.  The container init will replace then
+ * be running in the current process
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcExecContainerInit(const lxc_vm_def_t *vmDef)
+{
+    int rc = -1;
+    char* execString;
+    size_t execStringLen = strlen(vmDef->init) + 1 + 5;
+
+    if (NULL == (execString = calloc(execStringLen, sizeof(char)))) {
+       lxcError(NULL, NULL, VIR_ERR_NO_MEMORY,
+                 _("failed to calloc memory for init string: %s"),
+                 strerror(errno));
+        goto error_out;
+    }
+
+    strcpy(execString, "exec ");
+    strcat(execString, vmDef->init);
+
+    execl("/bin/sh", "sh", "-c", execString, (char*)NULL);
+    lxcError(NULL, NULL, VIR_ERR_NO_MEMORY,
+             _("execl failed to exec init: %s"), strerror(errno));
+
+error_out:
+    exit(rc);
+}
+
+/**
+ * lxcSetContainerStdio:
+ * @ttyName: Name of tty to set as the container console
+ *
+ * Sets the given tty as the primary conosole for the container as well as
+ * stdout, stdin and stderr.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetContainerStdio(const char *ttyName)
+{
+    int rc = -1;
+    int ttyfd;
+
+    if (setsid() < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("setsid failed: %s"), strerror(errno));
+        goto error_out;
+    }
+
+    ttyfd = open(ttyName, O_RDWR|O_NOCTTY);
+    if (ttyfd < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("open(%s) failed: %s"), ttyName, strerror(errno));
+        goto error_out;
+    }
+
+    if (ioctl(ttyfd, TIOCSCTTY, NULL) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("ioctl(TIOCSTTY) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    close(0); close(1); close(2);
+
+    if (dup2(ttyfd, 0) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stdin) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (dup2(ttyfd, 1) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stdout) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (dup2(ttyfd, 2) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stderr) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    rc = 0;
+
+cleanup:
+    close(ttyfd);
+
+error_out:
+    return rc;
+}
+
+/**
+ * lxcExecWithTty:
+ * @vm: Ptr to vm structure
+ *
+ * Sets container console and stdio and then execs container init
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcExecWithTty(lxc_vm_t *vm)
+{
+    int rc = -1;
+    lxc_vm_def_t *vmDef = vm->def;
+
+    if(lxcSetContainerStdio(vm->containerTty) < 0) {
+        goto exit_with_error;
+    }
+
+    lxcExecContainerInit(vmDef);
+
+exit_with_error:
+    exit(rc);
+}
+
+/**
+ * lxcChild:
+ * @argv: Pointer to container arguments
+ *
+ * This function is run in the process clone()'d in lxcStartContainer.
+ * Perform a number of container setup tasks:
+ *     Setup container file system
+ *     mount container /proca
+ * Then exec's the container init
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int lxcChild( void *argv )
+{
+    int rc = -1;
+    lxc_vm_t *vm = (lxc_vm_t *)argv;
+    lxc_vm_def_t *vmDef = vm->def;
+    lxc_mount_t *curMount;
+    int i;
+
+    if (NULL == vmDef) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("lxcChild() passed invalid vm definition"));
+        goto cleanup;
+    }
+
+    /* handle the bind mounts first before doing anything else that may */
+    /* then access those mounted dirs */
+    curMount = vmDef->mounts;
+    for (i = 0; curMount; curMount = curMount->next) {
+        rc = mount(curMount->source,
+                   curMount->target,
+                   NULL,
+                   MS_BIND,
+                   NULL);
+        if (0 != rc) {
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("failed to mount %s at %s for container: %s"),
+                     curMount->source, curMount->target, strerror(errno));
+            goto cleanup;
+        }
+    }
+
+    /* mount /proc */
+    rc = mount("lxcproc", "/proc", "proc", 0, NULL);
+    if (0 != rc) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("failed to mount /proc for container: %s"),
+                 strerror(errno));
+        goto cleanup;
+    }
+
+    rc = lxcExecWithTty(vm);
+    /* this function will only return if an error occured */
+
+cleanup:
+    return rc;
+}
+
+#endif /* WITH_LXC */
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
+
Index: b/src/lxc_container.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/src/lxc_container.h	2008-04-07 23:22:33.000000000 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * lxc_container.h: header file for fcns run inside container
+ *
+ * Authors:
+ *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LXC_CONTAINER_H
+#define LXC_CONTAINER_H
+
+#ifdef WITH_LXC
+
+/* Function declarations */
+int lxcChild( void *argv );
+
+#endif /* LXC_DRIVER_H */
+
+#endif /* LXC_CONTAINER_H */
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
+
Index: b/src/lxc_driver.c
===================================================================
--- a/src/lxc_driver.c	2008-04-07 23:22:25.000000000 -0700
+++ b/src/lxc_driver.c	2008-04-09 22:47:41.000000000 -0700
@@ -25,17 +25,22 @@
 
 #ifdef WITH_LXC
 
+#include <fcntl.h>
+#include <poll.h>
 #include <sched.h>
 #include <sys/utsname.h>
 #include <string.h>
 #include <sys/types.h>
+#include <termios.h>
 #include <unistd.h>
 #include <wait.h>
 
 #include "lxc_conf.h"
+#include "lxc_container.h"
 #include "lxc_driver.h"
 #include "driver.h"
 #include "internal.h"
+#include "util.h"
 
 /* debug macros */
 #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
@@ -375,6 +380,428 @@
     return lxcGenerateXML(dom->conn, driver, vm, vm->def);
 }
 
+/**
+ * lxcStartContainer:
+ * @conn: pointer to connection
+ * @driver: pointer to driver structure
+ * @vm: pointer to virtual machine structure
+ *
+ * Starts a container process by calling clone() with the namespace flags
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcStartContainer(virConnectPtr conn,
+                             lxc_driver_t* driver,
+                             lxc_vm_t *vm)
+{
+    int rc = -1;
+    int flags;
+    int stacksize = getpagesize() * 4;
+    void *stack, *stacktop;
+
+    /* allocate a stack for the container */
+    stack = malloc(stacksize);
+    if (!stack) {
+        lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+                 _("unable to allocate container stack"));
+        goto error_exit;
+    }
+    stacktop = (char*)stack + stacksize;
+
+    flags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWUSER|CLONE_NEWIPC|SIGCHLD;
+
+    vm->def->id = clone(lxcChild, stacktop, flags, (void *)vm);
+
+    DEBUG("clone() returned, %d", vm->def->id);
+
+    if (vm->def->id < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("clone() failed, %s"), strerror(errno));
+        goto error_exit;
+    }
+
+    lxcSaveConfig(NULL, driver, vm, vm->def);
+
+    rc = 0;
+
+error_exit:
+    return rc;
+}
+
+/**
+ * lxcPutTtyInRawMode:
+ * @conn: pointer to connection
+ * @ttyDev: file descriptor for tty
+ *
+ * Sets tty attributes via cfmakeraw()
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcPutTtyInRawMode(virConnectPtr conn, int ttyDev)
+{
+    int rc = -1;
+
+    struct termios ttyAttr;
+
+    if (tcgetattr(ttyDev, &ttyAttr) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 "tcgetattr() failed: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    cfmakeraw(&ttyAttr);
+
+    if (tcsetattr(ttyDev, TCSADRAIN, &ttyAttr) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 "tcsetattr failed: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    rc = 0;
+
+cleanup:
+    return rc;
+}
+
+/**
+ * lxcSetupTtyTunnel:
+ * @conn: pointer to connection
+ * @vmDef: pointer to virtual machine definition structure
+ * @ttyDev: pointer to int.  On success will be set to fd for master
+ * end of tty
+ *
+ * Opens and configures the parent side tty
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetupTtyTunnel(virConnectPtr conn,
+                             lxc_vm_def_t *vmDef,
+                             int* ttyDev)
+{
+    int rc = -1;
+    char *ptsStr;
+
+    if (0 < strlen(vmDef->tty)) {
+        *ttyDev = open(vmDef->tty, O_RDWR|O_NOCTTY|O_NONBLOCK);
+        if (*ttyDev < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "open() tty failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        rc = grantpt(*ttyDev);
+        if (rc < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "grantpt() failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        rc = unlockpt(*ttyDev);
+        if (rc < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "unlockpt() failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        /* get the name and print it to stdout */
+        ptsStr = ptsname(*ttyDev);
+        if (ptsStr == NULL) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "ptsname() failed");
+            goto setup_complete;
+        }
+        /* This value needs to be stored in the container configuration file */
+        if (STRNEQ(ptsStr, vmDef->tty)) {
+            strcpy(vmDef->tty, ptsStr);
+        }
+
+        /* Enter raw mode, so all characters are passed directly to child */
+        if (lxcPutTtyInRawMode(conn, *ttyDev) < 0) {
+            goto setup_complete;
+        }
+
+    } else {
+        *ttyDev = -1;
+    }
+
+    rc = 0;
+
+setup_complete:
+    if((0 != rc) && (*ttyDev > 0)) {
+        close(*ttyDev);
+    }
+
+    return rc;
+}
+
+/**
+ * lxcSetupContainerTty:
+ * @conn: pointer to connection
+ * @ttymaster: pointer to int.  On success, set to fd for master end
+ * @ttyName: On success, will point to string slave end of tty.  Caller
+ * must free when done (such as in lxcFreeVM).
+ *
+ * Opens and configures container tty.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetupContainerTty(virConnectPtr conn,
+                                int *ttymaster,
+                                char **ttyName)
+{
+    int rc = -1;
+    char tempTtyName[PATH_MAX];
+
+    *ttymaster = posix_openpt(O_RDWR|O_NOCTTY);
+    if (*ttymaster < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("posix_openpt failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (unlockpt(*ttymaster) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("unlockpt failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (0 != ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName))) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("ptsname_r failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    *ttyName = malloc(sizeof(char) * (strlen(tempTtyName) + 1));
+    if (NULL == ttyName) {
+        lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+                 _("unable to allocate container name string"));
+        goto cleanup;
+    }
+
+    strcpy(*ttyName, tempTtyName);
+
+    rc = 0;
+
+cleanup:
+    if (0 != rc) {
+        if (-1 != *ttymaster) {
+            close(*ttymaster);
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * lxcTtyForward:
+ * @fd1: Open fd
+ * @fd1: Open fd
+ *
+ * Forwards traffic between fds.  Data read from fd1 will be written to fd2
+ * Data read from fd2 will be written to fd1.  This process loops forever.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcTtyForward(int fd1, int fd2)
+{
+    int rc = -1;
+    int i;
+    char buf[2];
+    struct pollfd fds[2];
+    int numFds = 0;
+
+    if (0 <= fd1) {
+        fds[numFds].fd = fd1;
+        fds[numFds].events = POLLIN;
+        ++numFds;
+    }
+
+    if (0 <= fd2) {
+        fds[numFds].fd = fd2;
+        fds[numFds].events = POLLIN;
+        ++numFds;
+    }
+
+    if (0 == numFds) {
+        DEBUG0("No fds to monitor, return");
+        goto cleanup;
+    }
+
+    while (1) {
+        if ((rc = poll(fds, numFds, -1)) <= 0) {
+
+            if ((0 == rc) || (errno == EINTR) || (errno == EAGAIN)) {
+                continue;
+            }
+
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("poll returned error: %s"), strerror(errno));
+            goto cleanup;
+        }
+
+        for (i = 0; i < numFds; ++i) {
+            if (!fds[i].revents) {
+                continue;
+            }
+
+            if (fds[i].revents & POLLIN) {
+                if (1 != (saferead(fds[i].fd, buf, 1))) {
+                    lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("read of fd %d failed: %s"), i,
+                             strerror(errno));
+                    goto cleanup;
+                }
+
+                if (1 < numFds) {
+                    if (1 != (safewrite(fds[i ^ 1].fd, buf, 1))) {
+                        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 _("write to fd %d failed: %s"), i,
+                                 strerror(errno));
+                        goto cleanup;
+                    }
+
+                }
+
+            }
+
+        }
+
+    }
+
+    rc = 0;
+
+cleanup:
+    return rc;
+}
+
+/**
+ * lxcVmStart:
+ * @conn: pointer to connection
+ * @driver: pointer to driver structure
+ * @vm: pointer to virtual machine structure
+ *
+ * Starts a vm
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcVmStart(virConnectPtr conn,
+                      lxc_driver_t * driver,
+                      lxc_vm_t * vm)
+{
+    int rc = -1;
+    lxc_vm_def_t *vmDef = vm->def;
+
+    /* open parent tty */
+    if (lxcSetupTtyTunnel(conn, vmDef, &vm->parentTty) < 0) {
+        goto cleanup;
+    }
+
+    /* open container tty */
+    if (lxcSetupContainerTty(conn, &(vm->containerTtyFd), &(vm->containerTty)) < 0) {
+        goto cleanup;
+    }
+
+    /* fork process to handle the tty io forwarding */
+    if ((vm->pid = fork()) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("unable to fork tty forwarding process: %s"),
+                 strerror(errno));
+        goto cleanup;
+    }
+
+    if (vm->pid  == 0) {
+        /* child process calls forward routine */
+        lxcTtyForward(vm->parentTty, vm->containerTtyFd);
+    }
+
+    close(vm->parentTty);
+    close(vm->containerTtyFd);
+
+    rc = lxcStartContainer(conn, driver, vm);
+
+    if (rc == 0) {
+        vm->state = VIR_DOMAIN_RUNNING;
+        driver->ninactivevms--;
+        driver->nactivevms++;
+    }
+
+cleanup:
+    return rc;
+}
+
+/**
+ * lxcDomainStart:
+ * @dom: domain to start
+ *
+ * Looks up domain and starts it.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcDomainStart(virDomainPtr dom)
+{
+    int rc = -1;
+    virConnectPtr conn = dom->conn;
+    lxc_driver_t *driver = (lxc_driver_t *)(conn->privateData);
+    lxc_vm_t *vm = lxcFindVMByName(driver, dom->name);
+
+    if (!vm) {
+        lxcError(conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 "no domain with uuid");
+        goto cleanup;
+    }
+
+    rc = lxcVmStart(conn, driver, vm);
+
+cleanup:
+    return rc;
+}
+
+/**
+ * lxcDomainCreateAndStart:
+ * @conn: pointer to connection
+ * @xml: XML definition of domain
+ * @flags: Unused
+ *
+ * Creates a domain based on xml and starts it
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static virDomainPtr
+lxcDomainCreateAndStart(virConnectPtr conn,
+                        const char *xml,
+                        unsigned int flags ATTRIBUTE_UNUSED) {
+    lxc_driver_t *driver = (lxc_driver_t *)conn->privateData;
+    lxc_vm_t *vm;
+    lxc_vm_def_t *def;
+    virDomainPtr dom = NULL;
+
+    if (!(def = lxcParseVMDef(conn, xml, NULL))) {
+        goto return_point;
+    }
+
+    if (!(vm = lxcAssignVMDef(conn, driver, def))) {
+        lxcFreeVMDef(def);
+        goto return_point;
+    }
+
+    if (lxcSaveVMDef(conn, driver, vm, def) < 0) {
+        lxcRemoveInactiveVM(driver, vm);
+        return NULL;
+    }
+
+    if (lxcVmStart(conn, driver, vm) < 0) {
+        lxcRemoveInactiveVM(driver, vm);
+        goto return_point;
+    }
+
+    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+    if (dom) {
+        dom->id = vm->def->id;
+    }
+
+return_point:
+    return dom;
+}
 
 static int lxcStartup(void)
 {
@@ -469,7 +896,7 @@
     NULL, /* getCapabilities */
     lxcListDomains, /* listDomains */
     lxcNumDomains, /* numOfDomains */
-    NULL/*lxcDomainCreateLinux*/, /* domainCreateLinux */
+    lxcDomainCreateAndStart, /* domainCreateLinux */
     lxcDomainLookupByID, /* domainLookupByID */
     lxcDomainLookupByUUID, /* domainLookupByUUID */
     lxcDomainLookupByName, /* domainLookupByName */
@@ -493,7 +920,7 @@
     lxcDomainDumpXML, /* domainDumpXML */
     lxcListDefinedDomains, /* listDefinedDomains */
     lxcNumDefinedDomains, /* numOfDefinedDomains */
-    NULL, /* domainCreate */
+    lxcDomainStart, /* domainCreate */
     lxcDomainDefine, /* domainDefineXML */
     lxcDomainUndefine, /* domainUndefine */
     NULL, /* domainAttachDevice */
Index: b/src/lxc_conf.c
===================================================================
--- a/src/lxc_conf.c	2008-04-01 06:01:01.000000000 -0700
+++ b/src/lxc_conf.c	2008-04-08 13:38:43.000000000 -0700
@@ -819,6 +819,7 @@
 void lxcFreeVM(lxc_vm_t *vm)
 {
     lxcFreeVMDef(vm->def);
+    free(vm->containerTty);
     free(vm);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]