Quoting Stéphane Graber (stgra...@ubuntu.com): > On 05/15/2013 10:23 AM, Serge Hallyn wrote: > > 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. > > I think I'd have preferred storing the command arguments in > LXC_CLONE_ARGS instead of directly in argv. Doing so would allow us to > remove/add other arguments without breaking all existing hooks. > > The user could then do "set -- $LXC_CLONE_ARGS" and just use $1... as usual. > > But I'm not horribly opposed to the proposed implementation and the rest > looks good.
Actually, yeah that would let menot add the argv[] to run_lxc_hooks, and make the patch quite a bit shorter. I'll redo it like that. Please don't apply :) > Acked-by: Stéphane Graber <stgra...@ubuntu.com> > > > 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; > > } > > > > > -- > Stéphane Graber > Ubuntu developer > http://www.ubuntu.com > ------------------------------------------------------------------------------ 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