[lxc-devel] [PATCH] Add mechanism for container to notify host about end of boot

Serge Hallyn serge.hallyn at canonical.com
Fri Sep 14 19:20:21 UTC 2012


Quoting Christian Seiler (christian at iwakd.de):
> This patch adds a simple notification system that allows the container to
> notify the host (in particular, the lxc-start process) that the boot process
> has been completed successfully. It also adds an additional status BOOTING
> that lxc-info may return. This allows the administrator and scripts to
> distinguish between a fully-running container and a container that is still
> in the process of booting.
> 
> If nothing is added to the configuration file, the current behavior is not
> changed, i.e. after lxc-start finishes the initialization, the container is
> immediately put into the RUNNING state. This ensures backwards
> compatibility.
> 
> If lxc.notification.type is set to 'fifo', after lxc-start initialization
> the container is initially put into the state BOOTING. Also, the FIFO
> /var/lib/lxc/%s/notification-fifo is created and bind-mounted into the
> container, by default to /dev/lxc-notify, but this can be changed via the
> lxc.notification.path configuration setting.
> 
> Inside the container one may execute 'echo RUNNING > /dev/lxc-notify' or an
> equivalent command to notify lxc-start that the container has now booted.
> Similarly, 'echo STOPPING > /dev/lxc-notify' will change the status to
> STOPPING, which may be done on shutdown. Currently, only RUNNING and
> STOPPING are allowed, other states are ignored.
> 
> This patch only provides the LXC part for the notification system, the
> counterpart inside the container has to be provided separately. The
> interface has been kept extremely simple to facilitate this.
> 
> The choice of the option lxc.notification.type, as opposed to
> lxc.notification.enabled, is deliberate in order to make this extensible. If
> at some point there is some kind of standardized system for these types of
> notifications, it will be simple to just add a new value for the
> lxc.notification.type option.
> 
> Signed-off-by: Christian Seiler <christian at iwakd.de>
> Cc: Serge Hallyn <serge.hallyn at ubuntu.com>

The longish thread makes me think we should accept this patch, then see
whether and how to easily extend it.

A few comments below:

> Cc: Guido Jäkel <G.Jaekel at dnb.de>
> ---
>  src/lxc/Makefile.am    |    1 +
>  src/lxc/conf.c         |    8 +
>  src/lxc/conf.h         |    3 +
>  src/lxc/confile.c      |   34 +++++
>  src/lxc/notification.c |  349 ++++++++++++++++++++++++++++++++++++++++++++++++
>  src/lxc/notification.h |   50 +++++++
>  src/lxc/start.c        |   22 +++-
>  src/lxc/start.h        |    1 +
>  src/lxc/state.c        |    1 +
>  src/lxc/state.h        |    3 +-
>  10 files changed, 468 insertions(+), 4 deletions(-)
>  create mode 100644 src/lxc/notification.c
>  create mode 100644 src/lxc/notification.h
> 
> diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> index 7d86ad6..d976bf7 100644
> --- a/src/lxc/Makefile.am
> +++ b/src/lxc/Makefile.am
> @@ -32,6 +32,7 @@ liblxc_so_SOURCES = \
>  	freezer.c \
>  	checkpoint.c \
>  	restart.c \
> +	notification.h notification.c \
>  	error.h error.c \
>  	parse.c parse.h \
>  	cgroup.c cgroup.h \
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index 1450ca6..422b742 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -61,6 +61,7 @@
>  #include "log.h"
>  #include "lxc.h"	/* for lxc_cgroup_set() */
>  #include "caps.h"       /* for lxc_caps_last_cap() */
> +#include "notification.h"
>  
>  #if HAVE_APPARMOR
>  #include <apparmor.h>
> @@ -2253,6 +2254,11 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
>  		return -1;
>  	}
>  
> +	if (lxc_notification_mount_hook(name, lxc_conf)) {
> +		ERROR("failed to init notification mechanism for container '%s'.", name);
> +		return -1;
> +	}
> +
>  	if (setup_cgroup(name, &lxc_conf->cgroup)) {
>  		ERROR("failed to setup the cgroups for '%s'", name);
>  		return -1;
> @@ -2540,6 +2546,8 @@ void lxc_conf_free(struct lxc_conf *conf)
>  	if (conf->aa_profile)
>  		free(conf->aa_profile);
>  #endif
> +	if (conf->notification_path)
> +		free(conf->notification_path);
>  	lxc_clear_config_caps(conf);
>  	lxc_clear_cgroups(conf, "lxc.cgroup");
>  	lxc_clear_hooks(conf);
> diff --git a/src/lxc/conf.h b/src/lxc/conf.h
> index dcf79fe..5ed67ec 100644
> --- a/src/lxc/conf.h
> +++ b/src/lxc/conf.h
> @@ -31,6 +31,7 @@
>  #include <lxc/list.h>
>  
>  #include <lxc/start.h> /* for lxc_handler */
> +#include <lxc/notification.h> /* for notification types */
>  
>  enum {
>  	LXC_NET_EMPTY,
> @@ -237,6 +238,8 @@ struct lxc_conf {
>  #endif
>  	char *seccomp;  // filename with the seccomp rules
>  	int maincmd_fd;
> +	lxc_notification_type_t notification_type;
> +	char *notification_path;
>  };
>  
>  int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
> diff --git a/src/lxc/confile.c b/src/lxc/confile.c
> index 2d14e0f..f48b8c0 100644
> --- a/src/lxc/confile.c
> +++ b/src/lxc/confile.c
> @@ -53,6 +53,8 @@ static int config_ttydir(const char *, char *, struct lxc_conf *);
>  #if HAVE_APPARMOR
>  static int config_aa_profile(const char *, char *, struct lxc_conf *);
>  #endif
> +static int config_notification_type(const char *, char *, struct lxc_conf *);
> +static int config_notification_path(const char *, char *, struct lxc_conf *);
>  static int config_cgroup(const char *, char *, struct lxc_conf *);
>  static int config_mount(const char *, char *, struct lxc_conf *);
>  static int config_rootfs(const char *, char *, struct lxc_conf *);
> @@ -89,6 +91,8 @@ static struct lxc_config_t config[] = {
>  #if HAVE_APPARMOR
>  	{ "lxc.aa_profile",            config_aa_profile          },
>  #endif
> +	{ "lxc.notification.type",    config_notification_type    },
> +	{ "lxc.notification.path",    config_notification_path    },
>  	{ "lxc.cgroup",               config_cgroup               },
>  	{ "lxc.mount",                config_mount                },
>  	{ "lxc.rootfs.mount",         config_rootfs_mount         },
> @@ -880,6 +884,33 @@ static int config_aa_profile(const char *key, char *value, struct lxc_conf *lxc_
>  }
>  #endif
>  
> +static int config_notification_type(const char *key, char *value, struct lxc_conf *lxc_conf)
> +{
> +	lxc_notification_type_t notification_type = lxc_str2notification_type(value);
> +	if (notification_type == -1)
> +		return -1;
> +
> +	lxc_conf->notification_type = notification_type;
> +	return 0;
> +}
> +
> +static int config_notification_path(const char *key, char *value, struct lxc_conf *lxc_conf)
> +{
> +	char *path;
> +
> +	if (!value || strlen(value) == 0)
> +		return 0;
> +	path = strdup(value);
> +	if (!path) {
> +		SYSERROR("failed to strdup '%s': %m", value);
> +		return -1;
> +	}
> +
> +	lxc_conf->notification_path = path;
> +
> +	return 0;
> +}
> +
>  static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
>  {
>  	char *token = "lxc.cgroup.";
> @@ -1597,6 +1628,9 @@ void write_config(FILE *fout, struct lxc_conf *c)
>  	case PER_LINUX: fprintf(fout, "lxc.arch = x86_64\n"); break;
>  	default: break;
>  	}
> +	fprintf(fout, "lxc.notification.type = %s\n", lxc_notification_type2str(c->notification_type));
> +	if (c->notification_path)
> +		fprintf(fout, "lxc.notification.path = %s\n", c->notification_path);
>  #if HAVE_APPARMOR
>  	if (c->aa_profile)
>  		fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile);
> diff --git a/src/lxc/notification.c b/src/lxc/notification.c
> new file mode 100644
> index 0000000..d3d6602
> --- /dev/null
> +++ b/src/lxc/notification.c
> @@ -0,0 +1,349 @@
> +/*
> + * lxc: linux Container library
> + *
> + * (C) Copyright IBM Corp. 2007, 2008
> + *
> + * Authors:
> + * Daniel Lezcano <dlezcano at fr.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <sys/mount.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +
> +#include "notification.h"
> +#include "start.h"
> +#include "state.h"
> +#include "conf.h"
> +#include "mainloop.h"
> +#include "log.h"
> +
> +#define FIFO_EXTERNAL_PATH          "/var/lib/lxc/%s/notification-fifo"
> +#define FIFO_INTERNAL_PATH_DFLT     "/dev/lxc-notify"
> +
> +lxc_log_define(lxc_notification, lxc);
> +
> +static char *strnotification_type[] = {
> +	"none",
> +	"fifo",
> +};
> +
> +struct notification_data_fifo {
> +	int fd;
> +};
> +
> +const char *lxc_notification_type2str(lxc_notification_type_t type)
> +{
> +	if (type < LXC_NOTIFICATION_NONE || type > _LXC_NOTIFICATION_MAX - 1)
> +		return NULL;
> +	return strnotification_type[type];
> +}
> +
> +lxc_notification_type_t lxc_str2notification_type(const char *type)
> +{
> +	int i, len;
> +	len = sizeof(strnotification_type)/sizeof(strnotification_type[0]);
> +	for (i = 0; i < len; i++)
> +		if (!strcmp(strnotification_type[i], type))
> +			return i;
> +
> +	ERROR("invalid notification type '%s'", type);
> +	return -1;
> +}
> +
> +static int notification_init_fifo(struct lxc_handler *handler);
> +static int notification_mount_hook_fifo(const char *name, struct lxc_conf *conf);
> +static int notification_mainloop_add_fifo(const char *name, struct lxc_epoll_descr *descr,
> +                                          struct lxc_handler *handler);
> +static int notification_callback_fifo(int fd, void *data, struct lxc_epoll_descr *descr);
> +static int notification_fini_fifo(struct lxc_handler *handler);
> +
> +int lxc_notification_init(struct lxc_handler *handler)
> +{
> +	switch (handler->conf->notification_type) {
> +		case LXC_NOTIFICATION_NONE: return 0;
> +		case LXC_NOTIFICATION_FIFO: return notification_init_fifo(handler);
> +		default:
> +			ERROR("invalid notification type");
> +			return -1;
> +	}
> +}
> +
> +int lxc_notification_fini(struct lxc_handler *handler)
> +{
> +	switch (handler->conf->notification_type) {
> +		case LXC_NOTIFICATION_NONE: return 0;
> +		case LXC_NOTIFICATION_FIFO: return notification_fini_fifo(handler);
> +		default:
> +			ERROR("invalid notification type");
> +			return -1;
> +	}
> +}
> +
> +int lxc_notification_mount_hook(const char *name, struct lxc_conf *conf)
> +{
> +	switch (conf->notification_type) {
> +		case LXC_NOTIFICATION_NONE: return 0;
> +		case LXC_NOTIFICATION_FIFO: return notification_mount_hook_fifo(name, conf);
> +		default:
> +			ERROR("invalid notification type");
> +			return -1;
> +	}
> +}
> +
> +int lxc_notification_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
> +                                  struct lxc_handler *handler)
> +{
> +	switch (handler->conf->notification_type) {
> +		case LXC_NOTIFICATION_NONE: return 0;
> +		case LXC_NOTIFICATION_FIFO: return notification_mainloop_add_fifo(name, descr, handler);
> +		default:
> +			ERROR("invalid notification type");
> +			return -1;
> +	}
> +}
> +
> +lxc_state_t lxc_notification_initial_running_state(struct lxc_handler *handler)
> +{
> +	switch (handler->conf->notification_type) {
> +		case LXC_NOTIFICATION_NONE: return RUNNING;
> +		case LXC_NOTIFICATION_FIFO: return BOOTING;
> +		default: return RUNNING;
> +	}
> +}
> +
> +int notification_init_fifo(struct lxc_handler *handler)
> +{
> +	int ret;
> +	char external_name[MAXPATHLEN];
> +
> +	struct notification_data_fifo *d = malloc(sizeof(struct notification_data_fifo));

Please check return value.

> +	d->fd = -1;
> +
> +	snprintf(external_name, MAXPATHLEN, FIFO_EXTERNAL_PATH, handler->name);

Please do check return value here, unlikely as a problem may be.  (I dunno,
someone may compile with funky headers whre MAXPATHLEN = 256)

> +
> +	/* remove old object that was there before */
> +	unlink(external_name);
> +
> +	ret = mknod(external_name, S_IFIFO | 0600, 0);
> +	if (ret < 0) {
> +		SYSERROR("error creating notification FIFO %s", external_name);
> +		free(d);
> +		return -1;
> +	}
> +
> +	/* open it as O_RDWR so we don't get EOF and the pipe
> +	 * remains open over multiple programs writing to it
> +	 */
> +	d->fd = open(external_name, O_RDWR | O_NONBLOCK);
> +	if (d->fd < 0) {
> +		SYSERROR("error opening notification FIFO for reading");
> +		unlink(external_name);
> +		free(d);
> +		return -1;
> +	}
> +
> +	ret = fcntl(d->fd, F_SETFD, FD_CLOEXEC);
> +	if (ret < 0) {
> +		SYSERROR("error opening notification FIFO for reading (setting FD_CLOEXEC on fd)");
> +		close(d->fd);
> +		unlink(external_name);
> +		free(d);
> +		return -1;
> +	}
> +
> +	handler->notification_data = d;
> +	return 0;
> +}
> +
> +int notification_mount_hook_fifo(const char *name, struct lxc_conf *conf)
> +{
> +	int ret;
> +	char inside[MAXPATHLEN];
> +	char outside[MAXPATHLEN];
> +	const char *inside_path = FIFO_INTERNAL_PATH_DFLT;
> +
> +	if (conf->notification_path)
> +		inside_path = conf->notification_path;
> +
> +	if (inside_path[0] == '/')
> +		snprintf(inside, MAXPATHLEN, "%s%s", conf->rootfs.mount, inside_path);
> +	else
> +		snprintf(inside, MAXPATHLEN, "%s/%s", conf->rootfs.mount, inside_path);
> +
> +	snprintf(outside, MAXPATHLEN, FIFO_EXTERNAL_PATH, name);

Please check return values of all snprintf, but especially the ones using
inside_path are vulnerable.

> +	unlink(inside);
> +	ret = open(inside, O_CREAT | O_RDWR, 0600);
> +	if (ret < 0) {
> +		SYSERROR("could not create notification FIFO mountpoint inside container");
> +		return -1;
> +	}
> +	/* we just wanted to create the file so we can
> +	 * bind-mount the FIFO over it, we don't care at
> +	 * all about anything else
> +	 */
> +	close(ret);
> +
> +	ret = mount(outside, inside, NULL, MS_BIND, NULL);
> +	if (ret < 0) {
> +		SYSERROR("could not bind-mount notification FIFO into the container");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +int notification_mainloop_add_fifo(const char *name, struct lxc_epoll_descr *descr,
> +                                   struct lxc_handler *handler)
> +{
> +	struct notification_data_fifo *d = (struct notification_data_fifo *)handler->notification_data;
> +
> +	int ret;
> +
> +	if (!d) {
> +		ERROR("no notification fifo passed on");
> +		return -1;
> +	}
> +
> +	ret = lxc_mainloop_add_handler(descr, d->fd, notification_callback_fifo,
> +	                               handler);
> +	if (ret) {
> +		ERROR("failed to add handler for notification fifo");
> +		close(d->fd);
> +		d->fd = -1;
> +	}
> +
> +	return ret;
> +}
> +
> +int notification_callback_fifo(int fd, void *data, struct lxc_epoll_descr *descr)
> +{
> +	struct lxc_handler *handler = data;
> +	struct notification_data_fifo *d = (struct notification_data_fifo *)handler->notification_data;
> +
> +	int ret;
> +	char buf[256];
> +	char command[256];
> +	char *nl;
> +	char *ptr;
> +	lxc_state_t new_state;
> +
> +	ret = read(fd, buf, sizeof(buf) - 2);
> +	if (ret < 0) {
> +		/* ignore if this was a bogus poll event */
> +		if (errno == EAGAIN || errno == EINTR)
> +			return 0;
> +		SYSERROR("failed to read data from notification FIFO");
> +		return -1;
> +	} else if (ret == 0) {
> +		char external_name[MAXPATHLEN];
> +
> +		/* close and re-open the fifo, else we'll only
> +		 * continue to get EOFs
> +		 */
> +		lxc_mainloop_del_handler(descr, fd);
> +		close(fd);
> +
> +		snprintf(external_name, MAXPATHLEN, FIFO_EXTERNAL_PATH, handler->name);
> +		fd = open(external_name, O_RDWR | O_NONBLOCK);
> +		if (fd < 0) {
> +			SYSERROR("failed to re-open notification FIFO after unexpected EOF");
> +			d->fd = -1;
> +			return -1;
> +		}
> +		ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
> +		if (ret < 0) {
> +			SYSERROR("failed to re-open notification FIFO after unexpected EOF (setting FD_CLOEXEC on fd)");
> +			close(fd);
> +			d->fd = -1;
> +			return -1;
> +		}
> +
> +		d->fd = fd;
> +		ret = lxc_mainloop_add_handler(descr, d->fd, notification_callback_fifo,
> +		                               handler);
> +		if (ret < 0) {
> +			ERROR("failed to re-add mainloop handler for re-opened FIFO");
> +			return -1;
> +		}
> +
> +		return 0;
> +	}
> +
> +	/* make sure string is newline and zero-terminated,
> +	 * makes parsing easier */
> +	buf[ret] = '\n';
> +	buf[ret + 1] = '\0';
> +
> +	ptr = buf;
> +	nl = strstr(ptr, "\n");
> +	do {
> +		/* end of string */
> +		if (nl == NULL)
> +			break;
> +
> +		/* command is as large as buf, so this works */
> +		strncpy(command, ptr, nl - ptr);
> +		command[nl - ptr] = '\0';
> +
> +		ptr = nl + 1;
> +		nl = strstr(ptr, "\n");
> +
> +		if (strlen(command) == 0)
> +			continue;
> +
> +		new_state = lxc_str2state(command);
> +		switch (new_state) {
> +			case RUNNING:
> +			case STOPPING:
> +				ret = lxc_set_state(handler->name, handler, new_state);
> +				break;
> +			default:
> +				/* just ignore */
> +				break;
> +		}
> +	} while (ptr < buf + sizeof(buf) - 1);
> +
> +	return 0;
> +}
> +
> +int notification_fini_fifo(struct lxc_handler *handler)
> +{
> +	struct notification_data_fifo *d = (struct notification_data_fifo *)handler->notification_data;
> +
> +	char external_name[MAXPATHLEN];
> +
> +	if (d) {
> +		if (d->fd >= 0)
> +			close(d->fd);
> +		free(d);
> +		handler->notification_data = NULL;
> +	}
> +
> +	snprintf(external_name, MAXPATHLEN, FIFO_EXTERNAL_PATH, handler->name);
> +	unlink(external_name);
> +
> +	return 0;
> +}
> diff --git a/src/lxc/notification.h b/src/lxc/notification.h
> new file mode 100644
> index 0000000..3d3a621
> --- /dev/null
> +++ b/src/lxc/notification.h
> @@ -0,0 +1,50 @@
> +/*
> + * lxc: linux Container library
> + *
> + * (C) Copyright IBM Corp. 2007, 2008
> + *
> + * Authors:
> + * Daniel Lezcano <dlezcano at fr.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +#ifndef _notification_h
> +#define _notification_h
> +
> +#include "state.h"
> +
> +typedef enum {
> +	LXC_NOTIFICATION_NONE,
> +	LXC_NOTIFICATION_FIFO,
> +	_LXC_NOTIFICATION_MAX
> +} lxc_notification_type_t;
> +
> +struct lxc_handler;
> +struct lxc_conf;
> +struct lxc_epoll_descr;
> +
> +int lxc_notification_init(struct lxc_handler *handler);
> +int lxc_notification_mount_hook(const char *name, struct lxc_conf *conf);
> +int lxc_notification_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
> +                                  struct lxc_handler *handler);
> +int lxc_notification_fini(struct lxc_handler *handler);
> +lxc_state_t lxc_notification_initial_running_state(struct lxc_handler *handler);
> +
> +lxc_notification_type_t lxc_str2notification_type(const char *type);
> +const char *lxc_notification_type2str(lxc_notification_type_t type);
> +
> +
> +
> +#endif
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index 3e26b27..92fbc78 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -128,6 +128,7 @@ int signalfd(int fd, const sigset_t *mask, int flags)
>  #include "namespace.h"
>  #include "apparmor.h"
>  #include "lxcseccomp.h"
> +#include "notification.h"
>  
>  lxc_log_define(lxc_start, lxc);
>  
> @@ -334,6 +335,11 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
>  		ERROR("failed to add command handler to mainloop");
>  		goto out_mainloop_open;
>  	}
> +	
> +	if (lxc_notification_mainloop_add(name, &descr, handler)) {
> +		ERROR("failed to add notification handler to mainloop");
> +		goto out_mainloop_open;
> +	}
>  
>  	if (handler->conf->need_utmp_watch) {
>  		if (lxc_utmp_mainloop_add(&descr, handler)) {
> @@ -403,18 +409,25 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
>  		goto out_delete_tty;
>  	}
>  
> +	if (lxc_notification_init(handler)) {
> +		ERROR("failed to initialize notification support");
> +		goto out_delete_console;
> +	}
> +
>  	/* the signal fd has to be created before forking otherwise
>  	 * if the child process exits before we setup the signal fd,
>  	 * the event will be lost and the command will be stuck */
>  	handler->sigfd = setup_signal_fd(&handler->oldmask);
>  	if (handler->sigfd < 0) {
>  		ERROR("failed to set sigchild fd handler");
> -		goto out_delete_console;
> +		goto out_delete_notification;
>  	}
>  
>  	INFO("'%s' is initialized", name);
>  	return handler;
>  
> +out_delete_notification:
> +	lxc_notification_fini(handler);
>  out_delete_console:
>  	lxc_delete_console(&conf->console);
>  out_delete_tty:
> @@ -446,6 +459,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
>  
>  	lxc_delete_console(&handler->conf->console);
>  	lxc_delete_tty(&handler->conf->tty_info);
> +	lxc_notification_fini(handler);
>  	free(handler->name);
>  	free(handler);
>  }
> @@ -584,6 +598,7 @@ int lxc_spawn(struct lxc_handler *handler)
>  	int failed_before_rename = 0;
>  	const char *name = handler->name;
>  	int pinfd;
> +	lxc_state_t initial_running_state;
>  
>  	if (lxc_sync_init(handler))
>  		return -1;
> @@ -659,9 +674,10 @@ int lxc_spawn(struct lxc_handler *handler)
>  	if (handler->ops->post_start(handler, handler->data))
>  		goto out_abort;
>  
> -	if (lxc_set_state(name, handler, RUNNING)) {
> +	initial_running_state = lxc_notification_initial_running_state(handler);
> +	if (lxc_set_state(name, handler, initial_running_state)) {
>  		ERROR("failed to set state to %s",
> -			      lxc_state2str(RUNNING));
> +			      lxc_state2str(initial_running_state));
>  		goto out_abort;
>  	}
>  
> diff --git a/src/lxc/start.h b/src/lxc/start.h
> index 4b2e2b5..518189c 100644
> --- a/src/lxc/start.h
> +++ b/src/lxc/start.h
> @@ -49,6 +49,7 @@ struct lxc_handler {
>  #if HAVE_APPARMOR
>  	int aa_enabled;
>  #endif
> +	void *notification_data;
>  };
>  
>  extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *);
> diff --git a/src/lxc/state.c b/src/lxc/state.c
> index 466dc0a..e37d80f 100644
> --- a/src/lxc/state.c
> +++ b/src/lxc/state.c
> @@ -44,6 +44,7 @@ lxc_log_define(lxc_state, lxc);
>  static char *strstate[] = {
>  	"STOPPED", "STARTING", "RUNNING", "STOPPING",
>  	"ABORTING", "FREEZING", "FROZEN", "THAWED",
> +	"BOOTING",
>  };
>  
>  const char *lxc_state2str(lxc_state_t state)
> diff --git a/src/lxc/state.h b/src/lxc/state.h
> index 77b3424..ce09ba6 100644
> --- a/src/lxc/state.h
> +++ b/src/lxc/state.h
> @@ -25,7 +25,8 @@
>  
>  typedef enum {
>  	STOPPED, STARTING, RUNNING, STOPPING,
> -	ABORTING, FREEZING, FROZEN, THAWED, MAX_STATE,
> +	ABORTING, FREEZING, FROZEN, THAWED,
> +	BOOTING, MAX_STATE,
>  } lxc_state_t;
>  
>  extern int lxc_rmstate(const char *name);
> -- 
> 1.7.2.5
> 




More information about the lxc-devel mailing list