struct lxc_conf *lxc_conf_init(void)
{
struct lxc_conf *new;
+ int i;
new = malloc(sizeof(*new));
if (!new) {
lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
lxc_list_init(&new->caps);
+ for (i=0; i<NUM_LXC_HOOKS; i++)
+ lxc_list_init(&new->hooks[i]);
#if HAVE_APPARMOR
new->aa_profile = NULL;
#endif
return -1;
}
+ HOOK(name, "mount", lxc_conf);
if (setup_cgroup(name, &lxc_conf->cgroup)) {
ERROR("failed to setup the cgroups for '%s'", name);
return -1;
return 0;
}
+
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
+{
+ int which = -1;
+ struct lxc_list *it;
+
+ if (strcmp(hook, "pre-start") == 0)
+ which = LXCHOOK_PRESTART;
+ else if (strcmp(hook, "mount") == 0)
+ which = LXCHOOK_MOUNT;
+ else if (strcmp(hook, "start") == 0)
+ which = LXCHOOK_START;
+ else if (strcmp(hook, "post-stop") == 0)
+ which = LXCHOOK_POSTSTOP;
+ 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);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
* @aa_profile : apparmor profile to switch to
#endif
*/
+enum lxchooks {
+ LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START,
+ LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
struct lxc_conf {
char *fstab;
int tty;
struct lxc_rootfs rootfs;
char *ttydir;
int close_all_fds;
+ struct lxc_list hooks[NUM_LXC_HOOKS];
#if HAVE_APPARMOR
char *aa_profile;
#endif
#endif
};
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
+/* we don't want to stick with the HOOK define, it's just to easily start */
+#define HOOK(name, which, conf) \
+ do { \
+ int hookret = run_lxc_hooks(name, which, conf); \
+ if (hookret) return -1; \
+ } while (0);
+
/*
* Initialize the lxc configuration structure
*/
static int config_rootfs_mount(const char *, char *, struct lxc_conf *);
static int config_pivotdir(const char *, char *, struct lxc_conf *);
static int config_utsname(const char *, char *, struct lxc_conf *);
+static int config_hook(const char *key, char *value, struct lxc_conf *lxc_conf);
static int config_network_type(const char *, char *, struct lxc_conf *);
static int config_network_flags(const char *, char *, struct lxc_conf *);
static int config_network_link(const char *, char *, struct lxc_conf *);
{ "lxc.rootfs", config_rootfs },
{ "lxc.pivotdir", config_pivotdir },
{ "lxc.utsname", config_utsname },
+ { "lxc.hook.pre-start", config_hook },
+ { "lxc.hook.mount", config_hook },
+ { "lxc.hook.start", config_hook },
+ { "lxc.hook.post-stop", config_hook },
{ "lxc.network.type", config_network_type },
{ "lxc.network.flags", config_network_flags },
{ "lxc.network.link", config_network_link },
return -1;
}
+static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
+{
+ struct lxc_list *hooklist;
+
+ hooklist = malloc(sizeof(*hooklist));
+ if (!hooklist) {
+ free(hook);
+ return -1;
+ }
+ hooklist->elem = hook;
+ lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
+ return 0;
+}
+
+static int config_hook(const char *key, char *value,
+ struct lxc_conf *lxc_conf)
+{
+ char *copy = strdup(value);
+ if (!copy) {
+ SYSERROR("failed to dup string '%s'", value);
+ return -1;
+ }
+ if (strcmp(key, "lxc.hook.pre-start") == 0)
+ return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
+ else if (strcmp(key, "lxc.hook.mount") == 0)
+ return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
+ else if (strcmp(key, "lxc.hook.start") == 0)
+ 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);
+ SYSERROR("Unknown key: %s", key);
+ free(copy);
+ return -1;
+}
+
static int config_personality(const char *key, char *value,
struct lxc_conf *lxc_conf)
{
goto out_free_name;
}
+ HOOK(name, "pre-start", conf);
+
if (lxc_create_tty(name, conf)) {
ERROR("failed to create the ttys");
goto out_aborting;
lxc_set_state(name, handler, STOPPING);
lxc_set_state(name, handler, STOPPED);
+ HOOK(name, "post-stop", handler->conf);
+
/* reset mask set by setup_signal_fd */
if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
WARN("failed to restore sigprocmask");
close(handler->sigfd);
+ HOOK(handler->name, "start", handler->conf);
+
/* after this call, we are in error because this
* ops should not return as it execs */
if (handler->ops->start(handler, handler->data))