#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 *);
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, ...)
{
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;
}
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;
}
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;
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;
}
*/
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 {
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 setup_cgroup_devices(const char *cgpath, struct lxc_list *cgroups);
{ "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 },
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;
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");
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)
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]);
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");
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 */
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);
}
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];
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
*/
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);
}
/* 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;
}
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 */
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;
}