Quoting Christian Seiler (christ...@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 <christ...@iwakd.de> > Cc: Serge Hallyn <serge.hal...@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.jae...@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 > ------------------------------------------------------------------------------ Got visibility? Most devs has no idea what their production app looks like. Find out how fast your code is with AppDynamics Lite. http://ad.doubleclick.net/clk;262219671;13503038;y? http://info.appdynamics.com/FreeJavaPerformanceDownload.html _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel