Add a clone hook called from api_clone.  Pass arguments to it from
lxc_clone.c.

The clone update hook is called while the container's bdev is mounted.
Information about the container is passed in through environment
variables LXC_ROOTFS_PATH, LXC_NAME, The LXC_ROOTFS_MOUNT, and
LXC_CONFIG_FILE.

LXC_ROOTFS_MOUNT=/usr/lib/x86_64-linux-gnu/lxc
LXC_CONFIG_FILE=/var/lib/lxc/demo3/config
LXC_ROOTFS_PATH=/var/lib/lxc/demo3/rootfs
LXC_NAME=demo3

So from the hook, updates to the container should be made under
$LXC_ROOTFS_MOUNT/ .

The hook also receives command line arguments as follows:
First argument is container name, second is always 'lxc', third
is the hook name (always clone), then come the arguments which
were passed to lxc-clone.  I.e. when I did:

        sudo lxc-clone demo2 demo3 -- hey there dude

the arguments passed in were "demo3 lxc clone hey there dude"

I personally would like to drop the first two arguments.  The
name is available as $LXC_NAME, and the section argument ('lxc')
is meaningless.  However, doing so risks invalidating existing
hooks.

Soon analogous create and destroy hooks will be added as well.

Signed-off-by: Serge Hallyn <serge.hal...@ubuntu.com>
---
 src/lxc/conf.c         | 63 +++++++++++++++++++++++++++++++++++++++++++++-----
 src/lxc/conf.h         |  4 ++--
 src/lxc/confile.c      |  3 +++
 src/lxc/lxc_clone.c    | 16 ++++++-------
 src/lxc/lxccontainer.c | 55 ++++++++++++++++++++++++++++++-------------
 src/lxc/lxccontainer.h |  2 +-
 src/lxc/start.c        |  6 ++---
 7 files changed, 113 insertions(+), 36 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 746a2db..61e45b1 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -173,7 +173,7 @@ return -1;
 #endif
 
 char *lxchook_names[NUM_LXC_HOOKS] = {
-       "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop" };
+       "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", 
"clone" };
 
 typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
 
@@ -336,6 +336,55 @@ static int run_buffer(char *buffer)
        return 0;
 }
 
+static int run_script_argv(const char *name, const char *section,
+                     const char *script, const char *hook, char **argsin)
+{
+       int ret, i;
+       char *buffer;
+       size_t size = 0;
+
+       INFO("Executing script '%s' for container '%s', config section '%s'",
+            script, name, section);
+
+       for (i=0; argsin && argsin[i]; i++)
+               size += strlen(argsin[i]) + 1;
+
+       size += strlen(hook) + 1;
+
+       size += strlen(script);
+       size += strlen(name);
+       size += strlen(section);
+       size += 3;
+
+       if (size > INT_MAX)
+               return -1;
+
+       buffer = alloca(size);
+       if (!buffer) {
+               ERROR("failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(buffer, size, "%s %s %s %s", script, name, section, 
hook);
+       if (ret < 0 || ret >= size) {
+               ERROR("Script name too long");
+               return -1;
+       }
+
+       for (i=0; argsin && argsin[i]; i++) {
+               int len = size-ret;
+               int rc;
+               rc = snprintf(buffer + ret, len, " %s", argsin[i]);
+               if (rc < 0 || rc >= len) {
+                       ERROR("Script args too long");
+                       return -1;
+               }
+               ret += rc;
+       }
+
+       return run_buffer(buffer);
+}
+
 static int run_script(const char *name, const char *section,
                      const char *script, ...)
 {
@@ -2752,7 +2801,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
                return -1;
        }
 
-       if (run_lxc_hooks(name, "pre-mount", lxc_conf)) {
+       if (run_lxc_hooks(name, "pre-mount", lxc_conf, NULL)) {
                ERROR("failed to run pre-mount hooks for container '%s'.", 
name);
                return -1;
        }
@@ -2779,13 +2828,13 @@ int lxc_setup(const char *name, struct lxc_conf 
*lxc_conf)
                return -1;
        }
 
-       if (run_lxc_hooks(name, "mount", lxc_conf)) {
+       if (run_lxc_hooks(name, "mount", lxc_conf, NULL)) {
                ERROR("failed to run mount hooks for container '%s'.", name);
                return -1;
        }
 
        if (lxc_conf->autodev) {
-               if (run_lxc_hooks(name, "autodev", lxc_conf)) {
+               if (run_lxc_hooks(name, "autodev", lxc_conf, NULL)) {
                        ERROR("failed to run autodev hooks for container 
'%s'.", name);
                        return -1;
                }
@@ -2852,7 +2901,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
        return 0;
 }
 
-int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, char 
*argv[])
 {
        int which = -1;
        struct lxc_list *it;
@@ -2869,12 +2918,14 @@ int run_lxc_hooks(const char *name, char *hook, struct 
lxc_conf *conf)
                which = LXCHOOK_START;
        else if (strcmp(hook, "post-stop") == 0)
                which = LXCHOOK_POSTSTOP;
+       else if (strcmp(hook, "clone") == 0)
+               which = LXCHOOK_CLONE;
        else
                return -1;
        lxc_list_for_each(it, &conf->hooks[which]) {
                int ret;
                char *hookname = it->elem;
-               ret = run_script(name, "lxc", hookname, hook, NULL);
+               ret = run_script_argv(name, "lxc", hookname, hook, argv);
                if (ret)
                        return ret;
        }
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 465b1ec..5139aa3 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -237,7 +237,7 @@ struct lxc_rootfs {
  */
 enum lxchooks {
        LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
-       LXCHOOK_START, LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
+       LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, NUM_LXC_HOOKS};
 extern char *lxchook_names[NUM_LXC_HOOKS];
 
 struct saved_nic {
@@ -284,7 +284,7 @@ struct lxc_conf {
        char *rcfile;   // Copy of the top level rcfile we read
 };
 
-int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, char 
*argv[]);
 
 extern int setup_cgroup(const char *cgpath, struct lxc_list *cgroups);
 extern int detect_shared_rootfs(void);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index aec8177..fb851c9 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -117,6 +117,7 @@ static struct lxc_config_t config[] = {
        { "lxc.hook.autodev",         config_hook                 },
        { "lxc.hook.start",           config_hook                 },
        { "lxc.hook.post-stop",       config_hook                 },
+       { "lxc.hook.clone",           config_hook                 },
        { "lxc.network.type",         config_network_type         },
        { "lxc.network.flags",        config_network_flags        },
        { "lxc.network.link",         config_network_link         },
@@ -894,6 +895,8 @@ static int config_hook(const char *key, const char *value,
                return add_hook(lxc_conf, LXCHOOK_START, copy);
        else if (strcmp(key, "lxc.hook.post-stop") == 0)
                return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
+       else if (strcmp(key, "lxc.hook.clone") == 0)
+               return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
        SYSERROR("Unknown key: %s", key);
        free(copy);
        return -1;
diff --git a/src/lxc/lxc_clone.c b/src/lxc/lxc_clone.c
index b9c7a6e..2b0ee43 100644
--- a/src/lxc/lxc_clone.c
+++ b/src/lxc/lxc_clone.c
@@ -16,7 +16,7 @@
 
 lxc_log_define(lxc_clone, lxc);
 
-void usage(char *me)
+void usage(const char *me)
 {
        printf("Usage: %s [-s] [-B backingstore] [-L size] [-K] [-M] [-H]\n", 
me);
        printf("          [-p lxcpath] [-P newlxcpath] orig new\n");
@@ -60,6 +60,7 @@ int main(int argc, char *argv[])
        long newsize = 0;
        char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
        char *orig = NULL, *new = NULL, *vgname = NULL;
+       char **args = NULL;
        char c;
 
        if (argc < 3)
@@ -86,14 +87,13 @@ int main(int argc, char *argv[])
                default: break;
                }
        }
-       if (optind == argc-2 && !orig)
+    if (optind < argc && !orig)
                orig = argv[optind++];
-       if (optind == argc-1 && !new)
+    if (optind < argc && !new)
                new = argv[optind++];
-       if (optind < argc) {
-               printf("%d extraneous arguments\n", argc-optind);
-               usage(argv[0]);
-       }
+       if (optind < argc)
+               /* arguments for the clone hook */
+               args = &argv[optind];
        if (!new || !orig) {
                printf("Error: you must provide orig and new names\n");
                usage(argv[0]);
@@ -124,7 +124,7 @@ int main(int argc, char *argv[])
                lxc_container_put(c1);
                exit(1);
        }
-       c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize);
+       c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize, args);
        if (c2 == NULL) {
                lxc_container_put(c1);
                fprintf(stderr, "clone failed\n");
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index bac94c2..23db6f2 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -1364,16 +1364,14 @@ static int copy_storage(struct lxc_container *c0, 
struct lxc_container *c,
        return 0;
 }
 
-static int clone_update_rootfs(struct lxc_container *c, int flags)
+static int clone_update_rootfs(struct lxc_container *c, int flags, char 
**hookargs)
 {
        int ret = -1;
        char path[MAXPATHLEN];
        struct bdev *bdev;
        FILE *fout;
        pid_t pid;
-
-       if (flags & LXC_CLONE_KEEPNAME)
-               return 0;
+       struct lxc_conf *conf = c->lxc_conf;
 
        /* update hostname in rootfs */
        /* we're going to mount, so run in a clean namespace to simplify 
cleanup */
@@ -1393,17 +1391,41 @@ static int clone_update_rootfs(struct lxc_container *c, 
int flags)
                exit(1);
        if (bdev->ops->mount(bdev) < 0)
                exit(1);
-       ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               exit(1);
-       if (!(fout = fopen(path, "w"))) {
-               SYSERROR("unable to open %s: ignoring\n", path);
-               exit(0);
+
+       if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) {
+               /* Start of environment variable setup for hooks */
+               if (setenv("LXC_NAME", c->name, 1)) {
+                       SYSERROR("failed to set environment variable for 
container name");
+               }
+               if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) {
+                       SYSERROR("failed to set environment variable for config 
path");
+               }
+               if (setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) {
+                       SYSERROR("failed to set environment variable for rootfs 
mount");
+               }
+               if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) {
+                       SYSERROR("failed to set environment variable for rootfs 
mount");
+               }
+
+               if (run_lxc_hooks(c->name, "clone", conf, hookargs)) {
+                       ERROR("Error executing clone hook for %s", c->name);
+                       exit(1);
+               }
+       }
+
+       if (!(flags & LXC_CLONE_KEEPNAME)) {
+               ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       exit(1);
+               if (!(fout = fopen(path, "w"))) {
+                       SYSERROR("unable to open %s: ignoring\n", path);
+                       exit(0);
+               }
+               if (fprintf(fout, "%s", c->name) < 0)
+                       exit(1);
+               if (fclose(fout) < 0)
+                       exit(1);
        }
-       if (fprintf(fout, "%s", c->name) < 0)
-               exit(1);
-       if (fclose(fout) < 0)
-               exit(1);
        exit(0);
 }
 
@@ -1436,7 +1458,8 @@ static int create_file_dirname(char *path)
 
 struct lxc_container *lxcapi_clone(struct lxc_container *c, const char 
*newname,
                const char *lxcpath, int flags,
-               const char *bdevtype, const char *bdevdata, unsigned long 
newsize)
+               const char *bdevtype, const char *bdevdata, unsigned long 
newsize,
+               char **hookargs)
 {
        struct lxc_container *c2 = NULL;
        char newpath[MAXPATHLEN];
@@ -1525,7 +1548,7 @@ struct lxc_container *lxcapi_clone(struct lxc_container 
*c, const char *newname,
        if (!c2->save_config(c2, NULL))
                goto out;
 
-       if (clone_update_rootfs(c2, flags) < 0)
+       if (clone_update_rootfs(c2, flags, hookargs) < 0)
                goto out;
 
        // TODO: update c's lxc.snapshot = count
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index b6bd97c..67fbed4 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -105,7 +105,7 @@ struct lxc_container {
         */
        struct lxc_container *(*clone)(struct lxc_container *c, const char 
*newname,
                const char *lxcpath, int flags, const char *bdevtype,
-               const char *bdevdata, unsigned long newsize);
+               const char *bdevdata, unsigned long newsize, char **hookargs);
 
 #if 0
        bool (*commit_cgroups)(struct lxc_container *c);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index fd96d4f..995460e 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -461,7 +461,7 @@ struct lxc_handler *lxc_init(const char *name, struct 
lxc_conf *conf, const char
        }
        /* End of environment variable setup for hooks */
 
-       if (run_lxc_hooks(name, "pre-start", conf)) {
+       if (run_lxc_hooks(name, "pre-start", conf, NULL)) {
                ERROR("failed to run pre-start hooks for container '%s'.", 
name);
                goto out_aborting;
        }
@@ -513,7 +513,7 @@ static void lxc_fini(const char *name, struct lxc_handler 
*handler)
        lxc_set_state(name, handler, STOPPING);
        lxc_set_state(name, handler, STOPPED);
 
-       if (run_lxc_hooks(name, "post-stop", handler->conf))
+       if (run_lxc_hooks(name, "post-stop", handler->conf, NULL))
                ERROR("failed to run post-stop hooks for container '%s'.", 
name);
 
        /* reset mask set by setup_signal_fd */
@@ -676,7 +676,7 @@ static int do_start(void *data)
        if (lxc_seccomp_load(handler->conf) != 0)
                goto out_warn_father;
 
-       if (run_lxc_hooks(handler->name, "start", handler->conf)) {
+       if (run_lxc_hooks(handler->name, "start", handler->conf, NULL)) {
                ERROR("failed to run start hooks for container '%s'.", 
handler->name);
                goto out_warn_father;
        }
-- 
1.8.1.2


------------------------------------------------------------------------------
AlienVault Unified Security Management (USM) platform delivers complete
security visibility with the essential security capabilities. Easily and
efficiently configure, manage, and operate all of your security controls
from a single console and one unified framework. Download a free trial.
http://p.sf.net/sfu/alienvault_d2d
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to