]> git.proxmox.com Git - mirror_lxc.git/commitdiff
Replace lxc_execute by an intermediate lxc_init
authordlezcano <dlezcano>
Thu, 13 Nov 2008 15:21:55 +0000 (15:21 +0000)
committerdlezcano <dlezcano>
Thu, 13 Nov 2008 15:21:55 +0000 (15:21 +0000)
From: Daniel Lezcano <dlezcano@fr.ibm.com>

The main difference between lxc_start and lxc_execute is the latter creates
an intermediate process to wait for all the childs. That allows to support
daemons or orphan process group for the pid namespace.

Having such difference makes the code to be duplicate between the two
functions. So instead of doing this, I create an intermediate <init> program
which is in charge to launch the specified command. This command is the
lxc-init program taking different options:
 --mount-procfs : mount the proc filesystem before exec'ing the command
 --mount-sysfs : mount the sys filesystem before exec'ing the command

A double dash indicates the end of the options of lxc-init and the beginning
of the command to be launched.

To summarize:
 * lxc_execute function is no more.
 * lxc-execute command uses the lxc_start function and launch the specified
command via lxc-init

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/Makefile.am
src/lxc/execute.c [deleted file]
src/lxc/lxc.h
src/lxc/lxc_execute.c
src/lxc/lxc_init.c [new file with mode: 0644]
src/lxc/lxc_start.c
src/lxc/start.c

index fa7e3eccc8a04d06ab99463eb9d574c5158ad92d..e965db45ac3ea97034150e981572f170e54f3314 100644 (file)
@@ -1,4 +1,4 @@
-INCLUDES= -I$(top_srcdir)/src -DLXCPATH="\"$(localstatedir)/lxc\""
+INCLUDES= -I$(top_srcdir)/src -DLXCPATH="\"$(localstatedir)/lxc\"" -DLXCBINDIR="\"$(bindir)\""
 lib_LTLIBRARIES = liblxc.la
 pkginclude_HEADERS = \
                monitor.h \
@@ -17,7 +17,6 @@ liblxc_la_SOURCES = \
        destroy.c \
        start.c \
        stop.c \
-       execute.c \
        monitor.c monitor.h \
        kill.c \
        freezer.c \
@@ -46,6 +45,7 @@ bin_SCRIPTS = \
        lxc-checkconfig
 
 bin_PROGRAMS = \
+       lxc-init \
        lxc-create \
        lxc-destroy \
        lxc-stop \
@@ -63,6 +63,9 @@ bin_PROGRAMS = \
        lxc-restart \
        lxc-version
 
+lxc_init_SOURCES = lxc_init.c
+lxc_init_LDADD = liblxc.la
+
 lxc_create_SOURCES = lxc_create.c lxc_config.c lxc_config.h
 lxc_create_LDADD = liblxc.la
 
diff --git a/src/lxc/execute.c b/src/lxc/execute.c
deleted file mode 100644 (file)
index 95dc807..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <dlezcano at fr.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
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#undef _GNU_SOURCE
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <sys/file.h>
-#include <sys/mount.h>
-
-#include <lxc/lxc.h>
-
-LXC_TTY_HANDLER(SIGINT);
-LXC_TTY_HANDLER(SIGQUIT);
-
-int lxc_execute(const char *name, int argc, char *argv[], 
-               lxc_callback_t preexec, void *data)
-{
-       char init[MAXPATHLEN];
-       char *val = NULL, *vinit = "[vinit]";
-       int fd, lock, sv[2], sync = 0, err = -1;
-       pid_t pid;
-       int clone_flags;
-
-       lock = lxc_get_lock(name);
-       if (!lock) {
-               lxc_log_error("'%s' is busy", name);
-               return -1;
-       }
-
-       if (lock < 0) {
-               lxc_log_error("failed to acquire lock on '%s':%s",
-                             name, strerror(-lock));
-               return -1;
-       }
-
-       if (lxc_setstate(name, STARTING)) {
-               lxc_log_error("failed to set state %s", lxc_state2str(STARTING));
-               goto out;
-       }
-
-       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
-               lxc_log_syserror("failed to create communication socketpair");
-               goto err;
-       }
-
-       LXC_TTY_ADD_HANDLER(SIGINT);
-       LXC_TTY_ADD_HANDLER(SIGQUIT);
-
-       clone_flags = CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
-       if (conf_has_utsname(name))
-               clone_flags |= CLONE_NEWUTS;
-       if (conf_has_network(name))
-               clone_flags |= CLONE_NEWNET;
-
-       pid = fork_ns(clone_flags);
-       if (pid < 0) {
-               lxc_log_syserror("failed to fork into a new namespace");
-               goto err_fork_ns;
-       }
-
-       if (!pid) {
-
-               pid = fork();
-               if (pid < 0) {
-                       lxc_log_syserror("failed to fork");
-                       return 1;
-               }
-
-               if (!pid) {
-                       close(sv[1]);
-                       fcntl(sv[0], F_SETFD, FD_CLOEXEC);
-
-                       if (write(sv[0], &sync, sizeof(sync)) < 0) {
-                               lxc_log_syserror("failed to write socket");
-                               exit(1);
-                       }
-
-                       if (read(sv[0], &sync, sizeof(sync)) < 0) {
-                               lxc_log_syserror("failed to read socket");
-                               exit(1);
-                       }
-
-                       if (lxc_setup(name)) {
-                               lxc_log_error("failed to setup the container");
-                               goto error;
-                       }
-
-                       if (mount("proc", "/proc", "proc", 0, NULL)) {
-                               lxc_log_syserror("failed to mount '/proc'");
-                               goto error;
-                       }
-
-                       if (clone_flags & CLONE_NEWNET)
-                               if (mount("sysfs", "/sys", "sysfs", 0, NULL)) {
-                                       lxc_log_syserror("failed to mount '/sys'");
-                                       /* continue: non fatal error until sysfs not per
-                                          namespace */
-                               }
-
-                       if (preexec)
-                               if (preexec(name, argc, argv, data)) {
-                                       lxc_log_error("preexec callback has failed");
-                                       return -1;
-                               }
-
-                       execvp(argv[0], argv);
-                       lxc_log_syserror("failed to exec %s", argv[0]);
-               error:
-                       if (write(sv[0], &sync, sizeof(sync)) < 0)
-                               lxc_log_syserror("failed to write the socket");
-                       
-                       exit(1);
-               }
-
-               setsid();
-               close(0);
-               close(1);
-               close(2);
-
-               if (prctl(PR_SET_NAME, vinit, 0, 0, 0))
-                       lxc_log_syserror("failed to set process name");
-
-               close(sv[0]);
-               close(sv[1]);
-
-               for (;;) {
-                       int status;
-                       if (wait(&status) < 0) {
-                               if (errno == ECHILD)
-                                       exit(0);
-                               if (errno == EINTR)
-                                       continue;
-                               lxc_log_syserror("failed to wait child");
-                               exit(1);
-                       }
-               }
-       }
-
-       close(sv[0]);
-       
-       if (read(sv[1], &sync, sizeof(sync)) < 0) {
-               lxc_log_syserror("failed to read the socket");
-               goto err_pipe_read;
-       }
-
-       if (lxc_link_nsgroup(name, pid))
-               lxc_log_warning("cgroupfs not found: cgroup disabled");
-
-       if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
-               lxc_log_error("failed to create the configured network");
-               goto err_create_network;
-       }
-
-       if (write(sv[1], &sync, sizeof(sync)) < 0) {
-               lxc_log_syserror("failed to write the socket");
-               goto err_pipe_write;
-       }
-
-       err = read(sv[1], &sync, sizeof(sync));
-       if (err < 0) {
-               lxc_log_error("failed to read the socket");
-               goto err_pipe_read2;
-       }
-
-       if (err > 0) {
-               lxc_log_error("something went wrong with %d", pid);
-               /* TODO : check status etc ... */
-               waitpid(pid, NULL, 0);
-               goto err_child_failed;
-       }
-
-       snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
-               
-       fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
-       if (fd < 0) {
-               lxc_log_syserror("failed to open %s", init);
-               goto err_open;
-       }
-
-       if (!asprintf(&val, "%d", pid)) {
-               lxc_log_syserror("failed to allocate memory");
-               goto err_open;
-       }
-
-       if (write(fd, val, strlen(val)) < 0) {
-               lxc_log_syserror("failed to write init pid");
-               goto err_write;
-       }
-
-       if (lxc_setstate(name, RUNNING)) {
-               lxc_log_error("failed to set state to %s", lxc_state2str(RUNNING));
-               goto err_state_failed;
-       }
-
-wait_again:
-       if (waitpid(pid, NULL, 0) < 0) {
-               if (errno == EINTR) 
-                       goto wait_again;
-               lxc_log_syserror("failed to wait the pid %d", pid);
-               goto err_waitpid_failed;
-       }
-
-       if (lxc_setstate(name, STOPPING))
-               lxc_log_error("failed to set state %s", lxc_state2str(STOPPING));
-
-       if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
-               lxc_log_error("failed to destroy the network");
-
-       err = 0;
-out:
-       if (lxc_setstate(name, STOPPED))
-               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
-
-       lxc_unlink_nsgroup(name);
-       unlink(init);
-       free(val);
-       lxc_put_lock(lock);
-
-       return err;
-
-err_write:
-       close(fd);
-
-err_state_failed:
-err_child_failed:
-err_pipe_read2:
-err_pipe_write:
-       if (clone_flags & CLONE_NEWNET)
-               conf_destroy_network(name);
-err_create_network:
-err_pipe_read:
-err_open:
-err_waitpid_failed:
-       if (lxc_setstate(name, ABORTING))
-               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
-
-       kill(pid, SIGKILL);
-err_fork_ns:
-       LXC_TTY_DEL_HANDLER(SIGQUIT);
-       LXC_TTY_DEL_HANDLER(SIGINT);
-       close(sv[0]);
-       close(sv[1]);
-err:
-       goto out;
-}
index 810f7eb9d872192d8d61d2ad52475c9c28531757..04ccb5ee212bbc7dc2db1498943347ce29eec1cc 100644 (file)
@@ -48,9 +48,6 @@ extern "C" {
 
 struct lxc_mem_stat;
 
-typedef int (*lxc_callback_t)(const char *name, int argc, 
-                             char *argv[], void *data);
-
 /*
  * Create the container object. Creates the /lxc/<name> directory
  * and fills it with the files corresponding to the configuration
@@ -74,28 +71,10 @@ extern int lxc_destroy(const char *name);
 /*
  * Start the container previously created with lxc_create.
  * @name     : the name of the container
- * @argc     : the number of arguments of the command line
  * @argv     : an array of char * corresponding to the commande line
- * @prestart : hooks will be called just before the command execs
  * Returns 0 on sucess, < 0 otherwise
  */
-extern int lxc_start(const char *name, int argc, char *argv[], 
-                    lxc_callback_t prestart, void *data);
-
-/*
- * Create the container and start it directly, using the argc, argv 
- * parameter. This command is for application container.
- * At the end of the exec'ed command, the container will
- * automatically autodestroy.
- * @name    : the name of the container
- * @conf    : the configuration data
- * @argc    : the number of arguments of the command line
- * @argv    : an array of char * corresponding to the commande line
- * @preexec : hooks will be called just before the command execs
- * Returns 0 on success, < 0 otherwise
- */
-extern int lxc_execute(const char *name, int argc, char *argv[], 
-                      lxc_callback_t preexec, void *data);
+extern int lxc_start(const char *name, char *argv[]);
 
 /*
  * Stop the container previously started with lxc_start or lxc_exec
index 304464c062c17e7d9f206e71d1d88d6111120e47..dc3cec1a1c874c2ea0207b346ba31e31cd862cf0 100644 (file)
@@ -20,6 +20,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <libgen.h>
@@ -44,7 +45,7 @@ int main(int argc, char *argv[])
 {
        char opt;
        char *name = NULL, *file = NULL;
-       char **args;
+       static char **args;
        char path[MAXPATHLEN];
        int nbargs = 0;
        int autodestroy = 0;
@@ -67,7 +68,6 @@ int main(int argc, char *argv[])
        if (!name || !argv[optind] || !strlen(argv[optind]))
                usage(argv[0]);
 
-       args = &argv[optind];
        argc -= nbargs;
        
        if (lxc_config_init(&lxc_conf)) {
@@ -75,13 +75,9 @@ int main(int argc, char *argv[])
                goto out;
        }
 
-       if (file) {
-
-               if (lxc_config_read(file, &lxc_conf)) {
-                       fprintf(stderr, "invalid configuration file\n");
-                       goto out;
-               }
-
+       if (file && lxc_config_read(file, &lxc_conf)) {
+               fprintf(stderr, "invalid configuration file\n");
+               goto out;
        }
 
        snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
@@ -93,13 +89,27 @@ int main(int argc, char *argv[])
                autodestroy = 1;
        }
 
-       if (lxc_execute(name, argc, args, NULL, NULL)) {
+       /* lxc-init --mount-procfs -- .... */
+       args = malloc((argc + 3)*sizeof(*args));
+       if (!args) {
+               fprintf(stderr, "failed to allocate memory for '%s'\n", name);
+               goto out;
+       }
+
+       nbargs = 0;
+       args[nbargs++] = LXCBINDIR "/lxc-init";
+       args[nbargs++] = "--mount-procfs";
+       args[nbargs++] = "--";
+
+       for (opt = 0; opt < argc; opt++)
+               args[nbargs++] = argv[optind++];
+
+       if (lxc_start(name, args)) {
                fprintf(stderr, "failed to execute '%s'\n", name);
                goto out;
        }
 
        ret = 0;
-
 out:
        if (autodestroy) {
                if (lxc_destroy(name)) {
diff --git a/src/lxc/lxc_init.c b/src/lxc/lxc_init.c
new file mode 100644 (file)
index 0000000..e18eaef
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+#define _GNU_SOURCE
+#include <getopt.h>
+
+static int mount_sysfs;
+static int mount_procfs;
+
+static struct option options[] = {
+       { "mount-sysfs", no_argument, &mount_sysfs, 1 },
+       { "mount-procfs", no_argument, &mount_procfs, 1 },
+};
+
+int main(int argc, char *argv[])
+{
+       pid_t pid;
+
+       int nbargs = 0;
+       char **aargv;
+
+       while (1) {
+               int ret = getopt_long_only(argc, argv, "", options, NULL);
+               if (ret == -1)
+                       break;
+               if (ret == '?')
+                       exit(1);
+               nbargs++;
+       }
+
+       if (!argv[optind]) {
+               fprintf(stderr, "missing command to launch\n");
+               exit(1);
+       }
+
+       aargv = &argv[optind];
+       argc -= nbargs;
+
+       pid = fork();
+       
+       if (pid < 0)
+               exit(1);
+
+       if (!pid) {
+               
+               if (mount_sysfs && mount("sysfs", "/sys", "sysfs", 0, NULL)) {
+                       fprintf(stderr, "failed to mount '/sys'\n");
+                       exit(1);
+               }
+               
+               if (mount_procfs && mount("proc", "/proc", "proc", 0, NULL)) {
+                       fprintf(stderr, "failed to mount '/proc'\n");
+                       exit(1);
+               }
+
+               execvp(aargv[0], aargv);
+               fprintf(stderr, "failed to exec: %s\n", aargv[0]);
+               exit(1);
+       }
+
+       for (;;) {
+               int status;
+               if (wait(&status) < 0) {
+                       if (errno == ECHILD)
+                               exit(0);
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr, "failed to wait child\n");
+                       return 1;
+               }
+       }
+
+       return 0;
+}
index 6c8fb37f40627173e2102125a1d47c39bdace6c2..b626da51ff22f61ebc8a02ad56ad39edfade2402 100644 (file)
@@ -64,7 +64,7 @@ int main(int argc, char *argv[])
        args = &argv[optind];
        argc -= nbargs;
 
-       if (lxc_start(name, argc, args, NULL, NULL)) {
+       if (lxc_start(name, args)) {
                fprintf(stderr, "failed to start %s\n", name);
                return 1;
        }
index a6d0db34f79cc25b1a00d601cc0e1c178720e5f0..225cb1a32c6f4ecf8846ceb55348aa4691226272 100644 (file)
@@ -43,8 +43,7 @@
 LXC_TTY_HANDLER(SIGINT);
 LXC_TTY_HANDLER(SIGQUIT);
 
-int lxc_start(const char *name, int argc, char *argv[], 
-             lxc_callback_t prestart, void *data)
+int lxc_start(const char *name, char *argv[])
 {
        char init[MAXPATHLEN];
        char *val = NULL;
@@ -132,13 +131,6 @@ int lxc_start(const char *name, int argc, char *argv[],
                        goto out_child;
                }
 
-               /* If a callback has been passed, call it before doing exec */
-               if (prestart)
-                       if (prestart(name, argc, argv, data)) {
-                               lxc_log_error("prestart callback has failed");
-                               goto out_child;
-                       }
-
                if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
                        lxc_log_syserror("failed to remove CAP_SYS_BOOT capability");
                        goto out_child;