diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index ed8bef7e1..4b97de611 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -308,9 +308,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Init ID Sets the UID/GID to use for the init system, and subsequent commands. - Note that using a non-root uid when booting a system container will + Note that using a non-root UID when booting a system container will likely not work due to missing privileges. Setting the UID/GID is mostly - useful when running application container. + useful when running application containers. Defaults to: UID(0), GID(0) @@ -608,7 +608,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - @@ -651,15 +650,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Add a configuration option to specify a script to be executed after creating and configuring the network used - from the host side. The following arguments are passed - to the script: container name and config section name - (net) Additional arguments depend on the config section - employing a script hook; the following are used by the - network system: execution context (up), network type - (empty/veth/macvlan/phys), Depending on the network - type, other arguments may be passed: - veth/macvlan/phys. And finally (host-sided) device name. + from the host side. + + + In addition to the information available to all hooks. The + following information is provided to the script: + + + + LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'. + + + + + + LXC_HOOK_SECTION: the section type 'net'. + + + + + + LXC_NET_TYPE: the network type. This is one of the valid + network types listed here (e.g. 'macvlan', 'veth'). + + + + + + LXC_NET_PARENT: the parent device on the host. This is only + set for network types 'mavclan', 'veth', 'phys'. + + + + + + LXC_NET_PEER: the name of the peer device on the host. This is + only set for 'veth' network types. Note that this information + is only available when is set + to 1. + + + + + Whether this information is provided in the form of environment + variables or as arguments to the script depends on the value of + . If set to 1 then information is + provided in the form of environment variables. If set to 0 + information is provided as arguments to the script. + + Standard output from the script is logged at debug level. Standard error is not logged, but can be captured by the @@ -676,15 +716,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Add a configuration option to specify a script to be executed before destroying the network used from the - host side. The following arguments are passed to the - script: container name and config section name (net) - Additional arguments depend on the config section - employing a script hook; the following are used by the - network system: execution context (down), network type - (empty/veth/macvlan/phys), Depending on the network - type, other arguments may be passed: - veth/macvlan/phys. And finally (host-sided) device name. + host side. + + + In addition to the information available to all hooks. The + following information is provided to the script: + + + + LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'. + + + + + + LXC_HOOK_SECTION: the section type 'net'. + + + + + + LXC_NET_TYPE: the network type. This is one of the valid + network types listed here (e.g. 'macvlan', 'veth'). + + + + + + LXC_NET_PARENT: the parent device on the host. This is only + set for network types 'mavclan', 'veth', 'phys'. + + + + + + LXC_NET_PEER: the name of the peer device on the host. This is + only set for 'veth' network types. Note that this information + is only available when is set + to 1. + + + + + Whether this information is provided in the form of environment + variables or as arguments to the script depends on the value of + . If set to 1 then information is + provided in the form of environment variables. If set to 0 + information is provided as arguments to the script. + + Standard output from the script is logged at debug level. Standard error is not logged, but can be captured by the @@ -1636,9 +1717,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA at various times in a container's lifetime. - When a container hook is executed, information is passed both - as command line arguments and through environment variables. - The arguments are: + When a container hook is executed, additional information is passed + along. The argument can be used to + determine if the following arguments are passed as command line + arguments or through environment variables. The arguments are: Container name. Section (always 'lxc'). @@ -1652,13 +1734,38 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA The following environment variables are set: + LXC_CGNS_AWARE: indicator whether the container is + cgroup namespace aware. + LXC_CONFIG_FILE: the path to the container + configuration file. + LXC_HOOK_TYPE: the hook type (e.g. 'clone', 'mount', + 'pre-mount'). Note that the existence of this environment variable is + conditional on the value of . If it + is set to 1 then LXC_HOOK_TYPE will be set. + + LXC_HOOK_SECTION: the section type (e.g. 'lxc', + 'net'). Note that the existence of this environment variable is + conditional on the value of . If it + is set to 1 then LXC_HOOK_SECTION will be set. + + LXC_HOOK_VERSION: the version of the hooks. This + value is identical to the value of the container's + config item. If it is set to 0 then + old-style hooks are used. If it is set to 1 then new-style hooks are + used. + LXC_LOG_LEVEL: the container's log level. LXC_NAME: is the container's name. + LXC_[NAMESPACE IDENTIFIER]_NS: path under + /proc/PID/fd/ to a file descriptor referring to the container's + namespace. For each preserved namespace type there will be a separate + environment variable. These environment variables will only be set if + is set to 1. LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. - LXC_CONFIG_FILE: the path to the container configuration file. - LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. - LXC_ROOTFS_PATH: this is the lxc.rootfs.path entry for the container. Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. - LXC_CGNS_AWARE: indicated whether the container is cgroup namespace aware. - LXC_LOG_LEVEL: the container's log level. + LXC_ROOTFS_PATH: this is the lxc.rootfs.path entry + for the container. Note this is likely not where the mounted rootfs is + to be found, use LXC_ROOTFS_MOUNT for that. + LXC_SRC_NAME: in the case of the clone hook, this is + the original container's name. @@ -1666,6 +1773,33 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Standard error is not logged, but can be captured by the hook redirecting its standard error to standard output. + + + + + + + + To pass the arguments in new style via environment variables set to + 1 otherwise set to 0 to pass them as arguments. + This setting affects all hooks arguments that were traditionally + passed as arguments to the script. Specifically, it affects the + container name, section (e.g. 'lxc', 'net') and hook type (e.g. + 'clone', 'mount', 'pre-mount') arguments. If new-style hooks are + used then the arguments will be available as environment variables. + The container name will be set in LXC_NAME. (This is set + independently of the value used for this config item.) The section + will be set in LXC_HOOK_SECTION and the hook type will be set in + LXC_HOOK_TYPE. + It also affects how the paths to file descriptors referring to the + container's namespaces are passed. If set to 1 then for each + namespace a separate environment variable LXC_[NAMESPACE + IDENTIFIER]_NS will be set. If set to 0 then the paths will be + passed as arguments to the stop hook. + + + + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index e1973a10c..93d4d09f5 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -308,84 +308,167 @@ static int run_buffer(char *buffer) f = lxc_popen(buffer); if (!f) { - SYSERROR("Failed to popen() %s.", buffer); + SYSERROR("Failed to popen() %s", buffer); return -1; } output = malloc(LXC_LOG_BUFFER_SIZE); if (!output) { - ERROR("Failed to allocate memory for %s.", buffer); + ERROR("Failed to allocate memory for %s", buffer); lxc_pclose(f); return -1; } while (fgets(output, LXC_LOG_BUFFER_SIZE, f->f)) - DEBUG("Script %s with output: %s.", buffer, output); + DEBUG("Script %s with output: %s", buffer, output); free(output); ret = lxc_pclose(f); if (ret == -1) { - SYSERROR("Script exited with error."); + SYSERROR("Script exited with error"); return -1; } else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { - ERROR("Script exited with status %d.", WEXITSTATUS(ret)); + ERROR("Script exited with status %d", WEXITSTATUS(ret)); return -1; } else if (WIFSIGNALED(ret)) { - ERROR("Script terminated by signal %d.", WTERMSIG(ret)); + ERROR("Script terminated by signal %d", WTERMSIG(ret)); return -1; } return 0; } -static int run_script_argv(const char *name, const char *section, - const char *script, const char *hook, - const char *lxcpath, char **argsin) +int run_script_argv(const char *name, unsigned int hook_version, + const char *section, const char *script, + const char *hookname, char **argsin) { - int ret, i; + int buf_pos, i, ret; char *buffer; size_t size = 0; - INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".", - script, name, section); + if (hook_version == 0) + INFO("Executing script \"%s\" for container \"%s\", config " + "section \"%s\"", script, name, section); + else + INFO("Executing script \"%s\" for container \"%s\"", script, name); for (i = 0; argsin && argsin[i]; i++) size += strlen(argsin[i]) + 1; - size += strlen(hook) + 1; - - size += strlen("exec"); + size += sizeof("exec"); size += strlen(script); - size += strlen(name); - size += strlen(section); - size += 4; + size++; if (size > INT_MAX) - return -1; + return -EFBIG; buffer = alloca(size); - if (!buffer) { - ERROR("Failed to allocate memory."); - return -1; - } - ret = - snprintf(buffer, size, "exec %s %s %s %s", script, name, section, hook); - if (ret < 0 || (size_t)ret >= size) { - ERROR("Script name too long."); - return -1; + if (hook_version == 0) { + size += strlen(hookname); + size++; + + size += strlen(name); + size++; + + size += strlen(section); + size++; + + if (size > INT_MAX) + return -EFBIG; + + buf_pos = snprintf(buffer, size, "exec %s %s %s %s", script, name, section, hookname); + if (buf_pos < 0 || (size_t)buf_pos >= size) { + ERROR("Failed to create command line for script \"%s\"", script); + return -1; + } + } else { + buf_pos = snprintf(buffer, size, "exec %s", script); + if (buf_pos < 0 || (size_t)buf_pos >= size) { + ERROR("Failed to create command line for script \"%s\"", script); + return -1; + } + + ret = setenv("LXC_HOOK_TYPE", hookname, 1); + if (ret < 0) { + SYSERROR("Failed to set environment variable: " + "LXC_HOOK_TYPE=%s", hookname); + return -1; + } + TRACE("Set environment variable: LXC_HOOK_TYPE=%s", section); + + ret = setenv("LXC_HOOK_SECTION", section, 1); + if (ret < 0) { + SYSERROR("Failed to set environment variable: " + "LXC_HOOK_SECTION=%s", section); + return -1; + } + TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section); + + if (strcmp(section, "net") == 0) { + char *parent; + + if (!argsin[0]) + return -EINVAL; + + ret = setenv("LXC_NET_TYPE", argsin[0], 1); + if (ret < 0) { + SYSERROR("Failed to set environment variable: " + "LXC_NET_TYPE=%s", argsin[0]); + return -1; + } + TRACE("Set environment variable: LXC_NET_TYPE=%s", argsin[0]); + + parent = argsin[1] ? argsin[1] : ""; + + if (strcmp(argsin[0], "macvlan")) { + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } else if (strcmp(argsin[0], "phys")) { + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } else if (strcmp(argsin[0], "veth")) { + char *peer = argsin[2] ? argsin[2] : ""; + + ret = setenv("LXC_NET_PEER", peer, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PEER=%s", peer); + return -1; + } + TRACE("Set environment variable: LXC_NET_PEER=%s", peer); + + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } + } } 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."); + size_t len = size - buf_pos; + + ret = snprintf(buffer + buf_pos, len, " %s", argsin[i]); + if (ret < 0 || (size_t)ret >= len) { + ERROR("Failed to create command line for script \"%s\"", script); return -1; } - ret += rc; + buf_pos += ret; } return run_buffer(buffer); @@ -2484,6 +2567,7 @@ struct lxc_conf *lxc_conf_init(void) lxc_list_init(&new->limits); lxc_list_init(&new->sysctls); lxc_list_init(&new->procs); + new->hooks_version = 0; for (i = 0; i < NUM_LXC_HOOKS; i++) lxc_list_init(&new->hooks[i]); lxc_list_init(&new->groups); @@ -3068,7 +3152,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath remount_all_slave(); - if (run_lxc_hooks(name, "pre-mount", conf, lxcpath, NULL)) { + if (run_lxc_hooks(name, "pre-mount", conf, NULL)) { ERROR("failed to run pre-mount hooks for container '%s'.", name); return -1; } @@ -3177,13 +3261,13 @@ int lxc_setup(struct lxc_handler *handler) return -1; } - if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) { + 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 > 0) { - if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) { + if (run_lxc_hooks(name, "autodev", lxc_conf, NULL)) { ERROR("failed to run autodev hooks for container '%s'.", name); return -1; } @@ -3260,41 +3344,45 @@ int lxc_setup(struct lxc_handler *handler) return 0; } -int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, - const char *lxcpath, char *argv[]) +int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, + char *argv[]) { - int which = -1; struct lxc_list *it; + int which = -1; - if (strcmp(hook, "pre-start") == 0) + if (strcmp(hookname, "pre-start") == 0) which = LXCHOOK_PRESTART; - else if (strcmp(hook, "start-host") == 0) + else if (strcmp(hookname, "start-host") == 0) which = LXCHOOK_START_HOST; - else if (strcmp(hook, "pre-mount") == 0) + else if (strcmp(hookname, "pre-mount") == 0) which = LXCHOOK_PREMOUNT; - else if (strcmp(hook, "mount") == 0) + else if (strcmp(hookname, "mount") == 0) which = LXCHOOK_MOUNT; - else if (strcmp(hook, "autodev") == 0) + else if (strcmp(hookname, "autodev") == 0) which = LXCHOOK_AUTODEV; - else if (strcmp(hook, "start") == 0) + else if (strcmp(hookname, "start") == 0) which = LXCHOOK_START; - else if (strcmp(hook, "stop") == 0) + else if (strcmp(hookname, "stop") == 0) which = LXCHOOK_STOP; - else if (strcmp(hook, "post-stop") == 0) + else if (strcmp(hookname, "post-stop") == 0) which = LXCHOOK_POSTSTOP; - else if (strcmp(hook, "clone") == 0) + else if (strcmp(hookname, "clone") == 0) which = LXCHOOK_CLONE; - else if (strcmp(hook, "destroy") == 0) + else if (strcmp(hookname, "destroy") == 0) which = LXCHOOK_DESTROY; else return -1; + lxc_list_for_each(it, &conf->hooks[which]) { int ret; - char *hookname = it->elem; - ret = run_script_argv(name, "lxc", hookname, hook, lxcpath, argv); - if (ret) - return ret; + char *hook = it->elem; + + ret = run_script_argv(name, conf->hooks_version, "lxc", hook, + hookname, argv); + if (ret < 0) + return -1; } + return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index f7a2ed2a8..b7ddf1d3f 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -295,7 +295,11 @@ struct lxc_conf { struct lxc_rootfs rootfs; char *ttydir; int close_all_fds; - struct lxc_list hooks[NUM_LXC_HOOKS]; + + struct { + unsigned int hooks_version; + struct lxc_list hooks[NUM_LXC_HOOKS]; + }; char *lsm_aa_profile; unsigned int lsm_aa_allow_incomplete; @@ -408,7 +412,7 @@ extern struct lxc_conf *current_config; #endif extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, - const char *lxcpath, char *argv[]); + char *argv[]); extern int detect_shared_rootfs(void); extern struct lxc_conf *lxc_conf_init(void); extern void lxc_conf_free(struct lxc_conf *conf); @@ -453,6 +457,9 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d, unsigned long flags); extern int run_script(const char *name, const char *section, const char *script, ...); +extern int run_script_argv(const char *name, unsigned int hook_version, + const char *section, const char *script, + const char *hookname, char **argsin); extern int in_caplist(int cap, struct lxc_list *caps); extern int setup_sysctl_parameters(struct lxc_list *sysctls); extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 5a11d7828..cde4f3e86 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -92,6 +92,7 @@ lxc_config_define(ephemeral); lxc_config_define(execute_cmd); lxc_config_define(group); lxc_config_define(hooks); +lxc_config_define(hooks_version); lxc_config_define(idmaps); lxc_config_define(includefiles); lxc_config_define(init_cmd); @@ -168,11 +169,12 @@ static struct lxc_config_t config[] = { { "lxc.hook.destroy", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.hook.mount", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.hook.post-stop", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, - { "lxc.hook.start-host", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, - { "lxc.hook.pre-start", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.hook.pre-mount", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, + { "lxc.hook.pre-start", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.hook.start", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, + { "lxc.hook.start-host", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.hook.stop", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, + { "lxc.hook.version", false, set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, }, { "lxc.hook", false, set_config_hooks, get_config_hooks, clr_config_hooks, }, { "lxc.idmap", false, set_config_idmaps, get_config_idmaps, clr_config_idmaps, }, { "lxc.include", false, set_config_includefiles, get_config_includefiles, clr_config_includefiles, }, @@ -980,6 +982,29 @@ static int set_config_hooks(const char *key, const char *value, return -1; } +static int set_config_hooks_version(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + int ret; + unsigned int tmp; + + if (lxc_config_value_empty(value)) + return clr_config_hooks_version(key, lxc_conf, NULL); + + ret = lxc_safe_uint(value, &tmp); + if (ret < 0) + return -1; + + if (tmp > 1) { + ERROR("Invalid hook version specified. Currently only 0 " + "(legacy) and 1 are supported"); + return -1; + } + + lxc_conf->hooks_version = tmp; + return 0; +} + static int set_config_personality(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { @@ -3154,6 +3179,12 @@ static int get_config_hooks(const char *key, char *retv, int inlen, return fulllen; } +static int get_config_hooks_version(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + return lxc_get_conf_int(c, retv, inlen, c->hooks_version); +} + static int get_config_net(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { @@ -3688,6 +3719,14 @@ static inline int clr_config_hooks(const char *key, struct lxc_conf *c, return lxc_clear_hooks(c, key); } +static inline int clr_config_hooks_version(const char *key, struct lxc_conf *c, + void *data) +{ + /* default to legacy hooks version */ + c->hooks_version = 0; + return 0; +} + static inline int clr_config_net(const char *key, struct lxc_conf *c, void *data) { diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index c134947b2..2a578ea65 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2746,7 +2746,7 @@ static bool container_destroy(struct lxc_container *c, SYSERROR("Failed to set environment variable for console log"); /* End of environment variable setup for hooks */ - if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) { + if (run_lxc_hooks(c->name, "destroy", conf, NULL)) { ERROR("Failed to execute clone hook for \"%s\"", c->name); goto out; } @@ -3458,7 +3458,7 @@ static int clone_update_rootfs(struct clone_update_data *data) SYSERROR("failed to set environment variable for rootfs mount"); } - if (run_lxc_hooks(c->name, "clone", conf, c->get_config_path(c), hookargs)) { + if (run_lxc_hooks(c->name, "clone", conf, hookargs)) { ERROR("Error executing clone hook for %s", c->name); storage_put(bdev); return -1; diff --git a/src/lxc/namespace.c b/src/lxc/namespace.c index da434052a..d716676ed 100644 --- a/src/lxc/namespace.c +++ b/src/lxc/namespace.c @@ -87,13 +87,13 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags) * linux/fs/namespace.c:mntns_install(). */ const struct ns_info ns_info[LXC_NS_MAX] = { - [LXC_NS_USER] = {"user", CLONE_NEWUSER, "CLONE_NEWUSER"}, - [LXC_NS_MNT] = {"mnt", CLONE_NEWNS, "CLONE_NEWNS"}, - [LXC_NS_PID] = {"pid", CLONE_NEWPID, "CLONE_NEWPID"}, - [LXC_NS_UTS] = {"uts", CLONE_NEWUTS, "CLONE_NEWUTS"}, - [LXC_NS_IPC] = {"ipc", CLONE_NEWIPC, "CLONE_NEWIPC"}, - [LXC_NS_NET] = {"net", CLONE_NEWNET, "CLONE_NEWNET"}, - [LXC_NS_CGROUP] = {"cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP"} + [LXC_NS_USER] = { "user", CLONE_NEWUSER, "CLONE_NEWUSER", "LXC_USER_NS" }, + [LXC_NS_MNT] = { "mnt", CLONE_NEWNS, "CLONE_NEWNS", "LXC_MNT_NS" }, + [LXC_NS_PID] = { "pid", CLONE_NEWPID, "CLONE_NEWPID", "LXC_PID_NS" }, + [LXC_NS_UTS] = { "uts", CLONE_NEWUTS, "CLONE_NEWUTS", "LXC_UTS_NS" }, + [LXC_NS_IPC] = { "ipc", CLONE_NEWIPC, "CLONE_NEWIPC", "LXC_IPC_NS" }, + [LXC_NS_NET] = { "net", CLONE_NEWNET, "CLONE_NEWNET", "LXC_NET_NS" }, + [LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP, "CLONE_NEWCGROUP", "LXC_CGROUP_NS" } }; int lxc_namespace_2_cloneflag(const char *namespace) diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h index 02ec08885..7644fcd60 100644 --- a/src/lxc/namespace.h +++ b/src/lxc/namespace.h @@ -68,6 +68,7 @@ extern const struct ns_info { const char *proc_name; int clone_flag; const char *flag_name; + const char *env_name; } ns_info[LXC_NS_MAX]; #if defined(__ia64__) diff --git a/src/lxc/network.c b/src/lxc/network.c index 23febe6d2..734cfe4e0 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -204,9 +204,17 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd } if (netdev->upscript) { - err = run_script(handler->name, "net", netdev->upscript, "up", - "veth", veth1, (char*) NULL); - if (err) + char *argv[] = { + "veth", + netdev->link, + veth1, + NULL, + }; + + err = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->upscript, "up", argv); + if (err < 0) goto out_delete; } @@ -254,9 +262,16 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n } if (netdev->upscript) { - err = run_script(handler->name, "net", netdev->upscript, "up", - "macvlan", netdev->link, (char*) NULL); - if (err) + char *argv[] = { + "macvlan", + netdev->link, + NULL, + }; + + err = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->upscript, "up", argv); + if (err < 0) goto on_error; } @@ -323,6 +338,13 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) { + int ret; + char *argv[] = { + "phys", + netdev->link, + NULL, + }; + if (netdev->link[0] == '\0') { ERROR("No link for physical interface specified"); return -1; @@ -346,27 +368,34 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd */ netdev->priv.phys_attr.ifindex = netdev->ifindex; - if (netdev->upscript) { - int err; - err = run_script(handler->name, "net", netdev->upscript, - "up", "phys", netdev->link, (char*) NULL); - if (err) - return -1; - } + if (!netdev->upscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->upscript, "up", argv); + if (ret < 0) + return -1; return 0; } static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) { + int ret; + char *argv[] = { + "empty", + NULL, + }; + netdev->ifindex = 0; - if (netdev->upscript) { - int err; - err = run_script(handler->name, "net", netdev->upscript, - "up", "empty", (char*) NULL); - if (err) - return -1; - } + if (!netdev->upscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->upscript, "up", argv); + if (ret < 0) + return -1; + return 0; } @@ -387,34 +416,48 @@ static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = { static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) { - char *veth1; - int err; + int ret; + char *argv[] = { + "veth", + netdev->link, + NULL, + NULL, + }; + + if (!netdev->downscript) + return 0; if (netdev->priv.veth_attr.pair[0] != '\0') - veth1 = netdev->priv.veth_attr.pair; + argv[2] = netdev->priv.veth_attr.pair; else - veth1 = netdev->priv.veth_attr.veth1; + argv[2] = netdev->priv.veth_attr.veth1; + + ret = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "veth", veth1, (char*) NULL); - if (err) - return -1; - } return 0; } static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "macvlan", + netdev->link, + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "macvlan", netdev->link, - (char*) NULL); - if (err) - return -1; - } return 0; } @@ -425,27 +468,40 @@ static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev) static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "phys", + netdev->link, + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "phys", netdev->link, (char*) NULL); - if (err) - return -1; - } return 0; } static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "empty", + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "empty", (char*) NULL); - if (err) - return -1; - } return 0; } diff --git a/src/lxc/start.c b/src/lxc/start.c index a144d6f8f..5052e2d5a 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -612,6 +612,7 @@ on_error: int lxc_init(const char *name, struct lxc_handler *handler) { + int ret; const char *loglevel; struct lxc_conf *conf = handler->conf; @@ -656,11 +657,18 @@ int lxc_init(const char *name, struct lxc_handler *handler) loglevel = lxc_log_priority_to_string(lxc_log_get_level()); if (setenv("LXC_LOG_LEVEL", loglevel, 1)) SYSERROR("Failed to set environment variable LXC_LOG_LEVEL=%s", loglevel); + + if (conf->hooks_version == 0) + ret = setenv("LXC_HOOK_VERSION", "0", 1); + else + ret = setenv("LXC_HOOK_VERSION", "1", 1); + if (ret < 0) + SYSERROR("Failed to set environment variable LXC_HOOK_VERSION=%u", conf->hooks_version); /* End of environment variable setup for hooks. */ TRACE("set environment variables"); - if (run_lxc_hooks(name, "pre-start", conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "pre-start", conf, NULL)) { ERROR("Failed to run lxc.hook.pre-start for container \"%s\".", name); goto out_aborting; } @@ -708,8 +716,8 @@ out_close_maincmd_fd: void lxc_fini(const char *name, struct lxc_handler *handler) { int i, rc; + pid_t self; struct lxc_list *cur, *next; - pid_t self = getpid(); char *namespaces[LXC_NS_MAX + 1]; size_t namespace_count = 0; @@ -718,16 +726,37 @@ void lxc_fini(const char *name, struct lxc_handler *handler) */ lxc_set_state(name, handler, STOPPING); + self = getpid(); for (i = 0; i < LXC_NS_MAX; i++) { - if (handler->nsfd[i] != -1) { - rc = asprintf(&namespaces[namespace_count], "%s:/proc/%d/fd/%d", - ns_info[i].proc_name, self, handler->nsfd[i]); - if (rc == -1) { - SYSERROR("Failed to allocate memory."); - break; - } - ++namespace_count; + if (handler->nsfd[i] < 0) + continue; + + if (handler->conf->hooks_version == 0) + rc = asprintf(&namespaces[namespace_count], + "%s:/proc/%d/fd/%d", ns_info[i].proc_name, + self, handler->nsfd[i]); + else + rc = asprintf(&namespaces[namespace_count], + "/proc/%d/fd/%d", self, handler->nsfd[i]); + if (rc == -1) { + SYSERROR("Failed to allocate memory."); + break; } + + if (handler->conf->hooks_version == 0) { + namespace_count++; + continue; + } + + rc = setenv(ns_info[i].env_name, namespaces[namespace_count], 1); + if (rc < 0) + SYSERROR("Failed to set environment variable %s=%s", + ns_info[i].env_name, namespaces[namespace_count]); + else + TRACE("Set environment variable %s=%s", + ns_info[i].env_name, namespaces[namespace_count]); + + namespace_count++; } namespaces[namespace_count] = NULL; @@ -737,8 +766,10 @@ void lxc_fini(const char *name, struct lxc_handler *handler) if (!handler->conf->reboot && setenv("LXC_TARGET", "stop", 1)) SYSERROR("Failed to set environment variable: LXC_TARGET=stop."); - if (run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, namespaces)) - ERROR("Failed to run lxc.hook.stop for container \"%s\".", name); + if (handler->conf->hooks_version == 0) + rc = run_lxc_hooks(name, "stop", handler->conf, namespaces); + else + rc = run_lxc_hooks(name, "stop", handler->conf, NULL); while (namespace_count--) free(namespaces[namespace_count]); @@ -761,7 +792,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler) handler->conf->maincmd_fd = -1; } - if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "post-stop", handler->conf, NULL)) { ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name); if (handler->conf->reboot) { WARN("Container will be stopped instead of rebooted."); @@ -1022,7 +1053,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, handler->lxcpath, NULL)) { + if (run_lxc_hooks(handler->name, "start", handler->conf, NULL)) { ERROR("Failed to run lxc.hook.start for container \"%s\".", handler->name); goto out_warn_father; } @@ -1482,7 +1513,7 @@ static int lxc_spawn(struct lxc_handler *handler) SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr); /* Run any host-side start hooks */ - if (run_lxc_hooks(name, "start-host", conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "start-host", conf, NULL)) { ERROR("Failed to run lxc.hook.start-host for container \"%s\".", name); return -1; } diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c index f6fda5a05..8c19ea2b8 100644 --- a/src/tests/parse_config_file.c +++ b/src/tests/parse_config_file.c @@ -301,16 +301,16 @@ static int set_get_compare_clear_save_load_network( int main(int argc, char *argv[]) { + int ret; struct lxc_container *c; - int fd = -1; - int ret = EXIT_FAILURE; + int fd = -1, fret = EXIT_FAILURE; char tmpf[] = "lxc-parse-config-file-XXXXXX"; char retval[4096] = {0}; fd = mkstemp(tmpf); if (fd < 0) { lxc_error("%s\n", "Could not create temporary file"); - exit(ret); + exit(fret); } close(fd); @@ -1110,10 +1110,23 @@ int main(int argc, char *argv[]) goto non_test_error; } - ret = EXIT_SUCCESS; + ret = set_get_compare_clear_save_load(c, "lxc.hook.version", "1", tmpf, true); + if (ret < 0) { + lxc_error("%s\n", "lxc.hook.version"); + goto non_test_error; + } + + ret = set_get_compare_clear_save_load(c, "lxc.hook.version", "2", tmpf, true); + if (ret == 0) { + lxc_error("%s\n", "lxc.hook.version"); + goto non_test_error; + } + + fret = EXIT_SUCCESS; + non_test_error: (void)unlink(tmpf); (void)rmdir(dirname(c->configfile)); lxc_container_put(c); - exit(ret); + exit(fret); }