diff --git a/.gitignore b/.gitignore index a69ffdea9..26011e483 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,9 @@ config/missing config/libtool.m4 config/lt*.m4 config/bash/lxc +config/init/systemd/lxc-autostart-helper +config/init/systemd/lxc.service +config/init/sysvinit/lxc doc/*.1 doc/*.5 diff --git a/config/init/systemd/Makefile.am b/config/init/systemd/Makefile.am index de5ee5008..fc374c520 100644 --- a/config/init/systemd/Makefile.am +++ b/config/init/systemd/Makefile.am @@ -5,7 +5,17 @@ EXTRA_DIST = \ if INIT_SCRIPT_SYSTEMD SYSTEMD_UNIT_DIR = $(prefix)/lib/systemd/system -install-systemd: lxc.service lxc-devsetup +lxc-autostart-helper: ../sysvinit/lxc.in $(top_builddir)/config.status + $(AM_V_GEN)sed \ + -e 's|[@]SYSCONFDIR[@]|$(sysconfdir)|g' \ + -e 's|[@]LOCALSTATEDIR[@]|$(localstatedir)|g' \ + -e 's|[@]BINDIR[@]|$(bindir)|g' \ + < $< > $@-t && \ + chmod a+x $@-t && \ + mv $@-t $@ +BUILT_SOURCES = lxc-autostart-helper + +install-systemd: lxc.service lxc-devsetup lxc-autostart-helper $(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR) $(INSTALL_DATA) lxc.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/ @@ -13,7 +23,7 @@ uninstall-systemd: rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc.service rmdir $(DESTDIR)$(SYSTEMD_UNIT_DIR) || : -pkglibexec_SCRIPTS = lxc-devsetup +pkglibexec_SCRIPTS = lxc-devsetup lxc-autostart-helper install-data-local: install-systemd uninstall-local: uninstall-systemd diff --git a/config/init/systemd/lxc.service b/config/init/systemd/lxc.service.in similarity index 57% rename from config/init/systemd/lxc.service rename to config/init/systemd/lxc.service.in index aa20b91fb..5f155b6b0 100644 --- a/config/init/systemd/lxc.service +++ b/config/init/systemd/lxc.service.in @@ -1,13 +1,13 @@ [Unit] Description=LXC Container Initialization and Autoboot Code -After=syslog.target +After=syslog.target network.target [Service] Type=oneshot RemainAfterExit=yes -ExecStartPre=/usr/libexec/lxc/lxc-devsetup -ExecStart=/usr/libexec/lxc/lxc-startup start -ExecStop=/usr/libexec/lxc/lxc-startup stop +ExecStartPre=@libexecdir@/lxc/lxc-devsetup +ExecStart=@libexecdir@/lxc/lxc-autostart-helper start +ExecStop=@libexecdir@/lxc/lxc-autostart-helper stop # Environment=BOOTUP=serial # Environment=CONSOLETYPE=serial StandardOutput=syslog diff --git a/config/init/sysvinit/lxc b/config/init/sysvinit/lxc deleted file mode 100755 index 5ab3c4656..000000000 --- a/config/init/sysvinit/lxc +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# lxc Start/Stop LXC autoboot containers -# -# chkconfig: 345 99 01 -# description: Starts/Stops all LXC containers configured for autostart. -# -### BEGIN INIT INFO -# Provides: lxc -# Default-Start: 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Bring up/down LXC autostart containers -# Description: Bring up/down LXC autostart containers -### END INIT INFO - -# Source function library. -. /etc/init.d/functions - -# Check for needed utility program -[ -x /usr/bin/lxc-autostart ] || exit 1 - -# If libvirtd is providing the bridge, it might not be -# immediately available, so wait a bit for it before starting -# up the containers or else any that use the bridge will fail -# to start -wait_for_bridge() -{ - [ -f /etc/lxc/default.conf ] || { return 0; } - - BRNAME=`grep '^[ ]*lxc.network.link' /etc/lxc/default.conf | sed 's/^.*=[ ]*//'` - if [ -z "$BRNAME" ]; then - return 0 - fi - - for try in `seq 1 30`; do - ifconfig -a |grep "^$BRNAME" >/dev/null 2>&1 - if [ $? = 0 ]; then - return - fi - sleep 1 - done -} - -# See how we were called. -case "$1" in - start) - [ ! -f /var/lock/subsys/lxc ] || { exit 0; } - - # Start containers - wait_for_bridge - action $"Starting LXC containers: " /usr/bin/lxc-autostart - touch /var/lock/subsys/lxc - ;; - stop) - action $"Stopping LXC containers: " /usr/bin/lxc-autostart -a -A -s - rm -f /var/lock/subsys/lxc - ;; - restart|reload|force-reload) - $0 stop - $0 start - ;; - *) - echo $"Usage: $0 {start|stop|restart|reload|force-reload}" - exit 2 -esac -exit $? diff --git a/config/init/sysvinit/lxc.in b/config/init/sysvinit/lxc.in new file mode 100644 index 000000000..1a876a28d --- /dev/null +++ b/config/init/sysvinit/lxc.in @@ -0,0 +1,124 @@ +#!/bin/sh +# +# lxc Start/Stop LXC autoboot containers +# +# chkconfig: 345 99 01 +# description: Starts/Stops all LXC containers configured for autostart. +# +### BEGIN INIT INFO +# Provides: lxc +# Default-Start: 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Bring up/down LXC autostart containers +# Description: Bring up/down LXC autostart containers +### END INIT INFO + +sysconfdir="@SYSCONFDIR@" +bindir="@BINDIR@" +localstatedir="@LOCALSTATEDIR@" + +# These can be overridden in @SYSCONFDIR@/sysconfig/lxc + +# BOOTGROUPS - What groups should start on bootup? +# Comma separated list of groups. +# Leading comma, trailing comma or embedded double +# comma indicates when the NULL group should be run. +# Example (default): boot the onboot group first then the NULL group +BOOTGROUPS="onboot," + +# SHUTDOWNDELAY - Wait time for a container to shut down. +# ner shutdown can result in lengthy system +# shutdown times. Even 5 seconds per container can be +# too long. +SHUTDOWNDELAY=5 + +# OPTIONS can be used for anything else. +# If you want to boot everything then +# options can be "-a" or "-a -A". +OPTIONS= + +# STOPOPTS are stop options. The can be used for anything else to stop. +# If you want to kill containers fast, use -k +STOPOPTS="-a -A -s" + +# Source function library. +test ! -r "$sysconfdir"/rc.d/init.d/functions || + . "$sysconfdir"/rc.d/init.d/functions + +# Source any configurable options +test ! -r "$sysconfdir"/sysconfig/lxc || + . "$sysconfdir"/sysconfig/lxc + +# Check for needed utility program +[ -x "$bindir"/lxc-autostart ] || exit 1 + +# If libvirtd is providing the bridge, it might not be +# immediately available, so wait a bit for it before starting +# up the containers or else any that use the bridge will fail +# to start +wait_for_bridge() +{ + [ -f "$sysconfdir"/lxc/default.conf ] || { return 0; } + + which ifconfig >/dev/null 2>&1 + if [ $? = 0 ]; then + cmd="ifconfig -a" + else + which ip >/dev/null 2>&1 + if [ $? = 0 ]; then + cmd="ip link list" + fi + fi + [ -n cmd ] || { return 0; } + + BRNAME=`grep '^[ ]*lxc.network.link' "$sysconfdir"/lxc/default.conf | sed 's/^.*=[ ]*//'` + if [ -z "$BRNAME" ]; then + return 0 + fi + + for try in `seq 1 30`; do + eval $cmd |grep "^$BRNAME" >/dev/null 2>&1 + if [ $? = 0 ]; then + return + fi + sleep 1 + done +} + +# See how we were called. +case "$1" in + start) + [ ! -f "$localstatedir"/lock/subsys/lxc ] || { exit 0; } + + if [ -n "$BOOTGROUPS" ] + then + BOOTGROUPS="-g $BOOTGROUPS" + fi + + # Start containers + wait_for_bridge + # Start autoboot containers first then the NULL group "onboot,". + action $"Starting LXC autoboot containers: " /usr/bin/lxc-autostart $OPTIONS $BOOTGROUPS + touch "$localstatedir"/lock/subsys/lxc + ;; + stop) + if [ -n "$SHUTDOWNDELAY" ] + then + SHUTDOWNDELAY="-t $SHUTDOWNDELAY" + fi + + # The stop is serialized and can take excessive time. We need to avoid + # delaying the system shutdown / reboot as much as we can since it's not + # parallelized... Even 5 second timout may be too long. + action $"Stopping LXC containers: " "$bindir"/lxc-autostart $STOPOPTS $SHUTDOWNDELAY + rm -f "$localstatedir"/lock/subsys/lxc + ;; + restart|reload|force-reload) + $0 stop + $0 start + ;; + *) + echo $"Usage: $0 {start|stop|restart|reload|force-reload}" + exit 2 +esac +exit $? diff --git a/config/init/upstart/lxc.conf b/config/init/upstart/lxc.conf index d5131adc4..ab79aab04 100644 --- a/config/init/upstart/lxc.conf +++ b/config/init/upstart/lxc.conf @@ -6,6 +6,30 @@ stop on starting rc RUNLEVEL=[016] env LXC_AUTO="false" +# These can be overridden in /etc/default/lxc + +# BOOTGROUPS - What groups should start on bootup? +# Comma separated list of groups. +# Leading comma, trailing comma or embedded double +# comma indicates when the NULL group should be run. +# Example (default): boot the onboot group first then the NULL group +env BOOTGROUPS="onboot," + +# SHUTDOWNDELAY - Wait time for a container to shut down. +# Container shutdown can result in lengthy system +# shutdown times. Even 5 seconds per container can be +# too long. +env SHUTDOWNDELAY=5 + +# OPTIONS can be used for anything else. +# If you want to boot everything then +# options can be "-a" or "-a -A". +env OPTIONS= + +# STOPOPTS are stop options. The can be used for anything else to stop. +# If you want to kill containers fast, use -k +env STOPOPTS="-a -A -s" + pre-start script [ -f /etc/default/lxc ] && . /etc/default/lxc @@ -20,12 +44,28 @@ pre-start script [ "x$LXC_AUTO" = "xtrue" ] || exit 0 - lxc-autostart -L | while read line; do + if [ -n "$BOOTGROUPS" ] + then + BOOTGROUPS="-g $BOOTGROUPS" + fi + + # Process the "onboot" group first then the NULL group. + lxc-autostart -L $OPTIONS $BOOTGROUPS | while read line; do set -- $line (start lxc-instance NAME=$1 && sleep $2) || true done end script +# The stop is serialized and can take excessive time. We need to avoid +# delaying the system shutdown / reboot as much as we can since it's not +# parallelized... Even 5 second timout may be too long. post-stop script - lxc-autostart -a -A -s || true + [ -f /etc/default/lxc ] && . /etc/default/lxc + + if [ -n "$SHUTDOWNDELAY" ] + then + SHUTDOWNDELAY="-t $SHUTDOWNDELAY" + fi + + lxc-autostart $STOPOPTS $SHUTDOWNDELAY || true end script diff --git a/configure.ac b/configure.ac index 8185f3a58..ab6c48171 100644 --- a/configure.ac +++ b/configure.ac @@ -575,7 +575,9 @@ AC_CONFIG_FILES([ config/bash/lxc config/init/Makefile config/init/sysvinit/Makefile + config/init/sysvinit/lxc config/init/systemd/Makefile + config/init/systemd/lxc.service config/init/upstart/Makefile config/etc/Makefile config/templates/Makefile diff --git a/doc/lxc-autostart.sgml.in b/doc/lxc-autostart.sgml.in index 3d423dde4..3e12d5cc0 100644 --- a/doc/lxc-autostart.sgml.in +++ b/doc/lxc-autostart.sgml.in @@ -154,8 +154,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Comma separate list of groups to select - (defaults to those without a lxc.group). + Comma separated list of groups to select + (defaults to those without a lxc.group - the NULL group). + This option may be specified multiple times + and the arguments concatentated. The NULL or + empty group may be specified as a leading comma, + trailing comma, embedded double comma, or empty + argument where the NULL group should be processed. + Groups are processed in the order specified on the + command line. Multiple invocations of the -g option + may be freely intermixed with the comma separated + lists and will be combined in specified order. @@ -185,6 +194,69 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Autostart and System Boot + + + The lxc-autostart command is used as part of the + LXC system service, when enabled to run on host system at bootup and at + shutdown. It's used to select which containers to start in what order + and how much to delay between each startup when the host system boots. + + + + Each container can be part of any number of groups or no group at all. + Two groups are special. One is the NULL group, i.e. the container does + not belong to any group. The other group is the "onboot" group. + + + + When the system boots with the LXC service enabled, it will first + attempt to boot any containers with lxc.start.auto == 1 that is a member + of the "onboot" group. The startup will be in order of lxc.start.order. + If an lxc.start.delay has been specified, that delay will be honored + before attempting to start the next container to give the current + container time to begin initialization and reduce overloading the host + system. After starting the members of the "onboot" group, the LXC system + will proceed to boot containers with lxc.start.auto == 1 which are not + members of any group (the NULL group) and proceed as with the onboot + group. + + + + + Startup Group Examples + + + + + + + + Start the "onboot" group first then the NULL group. + + + This is the equivalent of: . + + + + + + + + + + Starts the "dns" group first, the "web" group second, then + the NULL group followed by the "onboot" group. + + + This is the equivalent of: or . + + + + + + &seealso; diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index c7b36a4f0..30fe4a815 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1486,6 +1486,29 @@ mknod errno 0 + + + Autostart and System Boot + + Each container can be part of any number of groups or no group at all. + Two groups are special. One is the NULL group, i.e. the container does + not belong to any group. The other group is the "onboot" group. + + + + When the system boots with the LXC service enabled, it will first + attempt to boot any containers with lxc.start.auto == 1 that is a member + of the "onboot" group. The startup will be in order of lxc.start.order. + If an lxc.start.delay has been specified, that delay will be honored + before attempting to start the next container to give the current + container time to begin initialization and reduce overloading the host + system. After starting the members of the "onboot" group, the LXC system + will proceed to boot containers with lxc.start.auto == 1 which are not + members of any group (the NULL group) and proceed as with the onboot + group. + + + diff --git a/lxc.spec.in b/lxc.spec.in index 2717c8379..57912a1fe 100644 --- a/lxc.spec.in +++ b/lxc.spec.in @@ -154,6 +154,7 @@ rm -rf %{buildroot} %attr(4111,root,root) %{_libexecdir}/%{name}/lxc-user-nic %if %{with_systemd} %attr(555,root,root) %{_libexecdir}/%{name}/lxc-devsetup +%attr(555,root,root) %{_libexecdir}/%{name}/lxc-autostart-helper %endif %if %{with_python} diff --git a/src/lxc/lxc_autostart.c b/src/lxc/lxc_autostart.c index 1e0c60858..920de67cf 100644 --- a/src/lxc/lxc_autostart.c +++ b/src/lxc/lxc_autostart.c @@ -28,6 +28,9 @@ #include "log.h" lxc_log_define(lxc_autostart_ui, lxc); +static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list); + +struct lxc_list *cmd_groups_list = NULL; static int my_parser(struct lxc_arguments* args, int c, char* arg) { @@ -38,7 +41,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) case 's': args->shutdown = 1; break; case 'a': args->all = 1; break; case 'A': args->ignore_auto = 1; break; - case 'g': args->groups = arg; break; + case 'g': cmd_groups_list = accumulate_list( arg, ",", cmd_groups_list); break; case 't': args->timeout = atoi(arg); break; } return 0; @@ -79,6 +82,29 @@ Options:\n\ .timeout = 60, }; +int list_contains_entry( char *str_ptr, struct lxc_list *p1 ) { + struct lxc_list *it1; + + /* + * If the entry is NULL or the empty string and the list + * is NULL, we have a match + */ + if (! p1 && ! str_ptr) + return 1; + if (! p1 && ! *str_ptr) + return 1; + + if (!p1) + return 0; + + lxc_list_for_each(it1, p1) { + if (strcmp(it1->elem, str_ptr) == 0) + return 1; + } + + return 0; +} + int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) { struct lxc_list *it1; struct lxc_list *it2; @@ -102,6 +128,78 @@ int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) { return 0; } +/* + * This is a variation of get_list below it. + * This version allows two additional features. + * If a list is passed to it, it adds to it. + * It allows for empty entries (i.e. "group1,,group2") generating + * and empty list entry. + */ +static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) { + char *workstr = NULL; + char *workptr = NULL; + char *next_ptr = NULL; + struct lxc_list *worklist; + struct lxc_list *workstr_list; + + workstr = strdup(input); + if (!workstr) { + return NULL; + } + + workstr_list = str_list; + if ( ! workstr_list ) { + workstr_list = malloc(sizeof(*workstr_list)); + lxc_list_init(workstr_list); + } + + for (workptr = workstr; workptr; workptr = next_ptr) { + /* + * We can't use strtok_r here because it collapses + * multiple delimiters into 1 making empty fields + * impossible... + */ + /* token = strtok_r(workptr, delimiter, &sptr); */ + next_ptr = strchr( workptr, *delimiter ); + + if( next_ptr ) { + *next_ptr++ = '\0'; + } + + /* + * At this point, we'd like to check to see if this + * group is already contained in the list and ignore + * it if it is... This also helps us with any + * corner cases where a string begins or ends with a + * delimiter. + */ + + if ( list_contains_entry( workptr, workstr_list ) ) { + if ( *workptr ) { + fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr ); + } else { + fprintf(stderr, "Duilicate NULL group in list - ignoring\n" ); + } + } else { + worklist = malloc(sizeof(*worklist)); + if (!worklist) + break; + + worklist->elem = strdup(workptr); + if (!worklist->elem) { + free(worklist); + break; + } + + lxc_list_add_tail(workstr_list, worklist); + } + } + + free(workstr); + + return workstr_list; +} + static struct lxc_list *get_list(char *input, char *delimiter) { char *workstr = NULL; char *workptr = NULL; @@ -209,15 +307,29 @@ static int cmporder(const void *p1, const void *p2) { return (c1_order - c2_order) * -1; } +static int toss_list( struct lxc_list *c_groups_list ) { + struct lxc_list *it, *next; + + if (c_groups_list) { + lxc_list_for_each_safe(it, c_groups_list, next) { + lxc_list_del(it); + free(it->elem); + free(it); + } + free(c_groups_list); + } + + return 1; +} + int main(int argc, char *argv[]) { int count = 0; int i = 0; int ret = 0; struct lxc_container **containers = NULL; - struct lxc_list *cmd_groups_list = NULL; - struct lxc_list *c_groups_list = NULL; - struct lxc_list *it, *next; + struct lxc_list **c_groups_lists = NULL; + struct lxc_list *cmd_group; char *const default_start_args[] = { "/sbin/init", NULL, @@ -236,113 +348,167 @@ int main(int argc, char *argv[]) if (count < 0) return 1; + if (!my_args.all) { + /* Allocate an array for our container group lists */ + c_groups_lists = calloc( count, sizeof( struct lxc_list * ) ); + } + qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder); - if (my_args.groups && !my_args.all) - cmd_groups_list = get_list((char*)my_args.groups, ","); + if (cmd_groups_list && my_args.all) { + fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides."); + } - for (i = 0; i < count; i++) { - struct lxc_container *c = containers[i]; + if (!cmd_groups_list) { + /* + * We need a default cmd_groups_list even for the -a + * case in order to force a pass through the loop for + * the NULL group. This, someday, could be taken from + * a config file somewhere... + */ + cmd_groups_list = accumulate_list( "" , ",", NULL ); + } - if (!c->may_control(c)) { - lxc_container_put(c); - continue; - } + lxc_list_for_each(cmd_group, cmd_groups_list) { - if (!my_args.ignore_auto && - get_config_integer(c, "lxc.start.auto") != 1) { - lxc_container_put(c); - continue; - } + /* + * Prograpmmers Note: + * Because we may take several passes through the container list + * We'll switch on if the container pointer is NULL and if we process a + * container (run it or decide to ignore it) and call lxc_container_put + * then we'll NULL it out and not check it again. + */ + for (i = 0; i < count; i++) { + struct lxc_container *c = containers[i]; - if (!my_args.all) { - /* Filter by group */ - c_groups_list = get_config_list(c, "lxc.group"); + if (!c) + /* Skip - must have been already processed */ + continue; - ret = lists_contain_common_entry(cmd_groups_list, c_groups_list); - - if (c_groups_list) { - lxc_list_for_each_safe(it, c_groups_list, next) { - lxc_list_del(it); - free(it->elem); - free(it); - } - free(c_groups_list); - } - - if (ret == 0) { - lxc_container_put(c); + /* + * We haven't loaded the container groups yet so + * these next two checks don't need to free them + * if they fail. They'll fail on the first pass. + */ + if (!c->may_control(c)) { + /* We're done with this container */ + if ( lxc_container_put(c) > 0 ) + containers[i] = NULL; continue; } - } - c->want_daemonize(c, 1); + if (!my_args.ignore_auto && + get_config_integer(c, "lxc.start.auto") != 1) { + /* We're done with this container */ + if ( lxc_container_put(c) > 0 ) + containers[i] = NULL; + continue; + } - if (my_args.shutdown) { - /* Shutdown the container */ - if (c->is_running(c)) { - if (my_args.list) - printf("%s\n", c->name); - else { - if (!c->shutdown(c, my_args.timeout)) { - if (!c->stop(c)) { - fprintf(stderr, "Error shutting down container: %s\n", c->name); + if (!my_args.all) { + /* Filter by group */ + if( ! c_groups_lists[i] ) { + /* Now we're loading up a container's groups */ + c_groups_lists[i] = get_config_list(c, "lxc.group"); + } + + ret = list_contains_entry(cmd_group->elem, c_groups_lists[i]); + + if ( ret == 0 ) { + /* Not in the target group this pass */ + /* Leave in the list for subsequent passes */ + continue; + } + } + + /* We have a candidate continer to process */ + c->want_daemonize(c, 1); + + if (my_args.shutdown) { + /* Shutdown the container */ + if (c->is_running(c)) { + if (my_args.list) + printf("%s\n", c->name); + else { + if (!c->shutdown(c, my_args.timeout)) { + if (!c->stop(c)) { + fprintf(stderr, "Error shutting down container: %s\n", c->name); + } } } } } - } - else if (my_args.hardstop) { - /* Kill the container */ - if (c->is_running(c)) { - if (my_args.list) - printf("%s\n", c->name); - else { - if (!c->stop(c)) - fprintf(stderr, "Error killing container: %s\n", c->name); + else if (my_args.hardstop) { + /* Kill the container */ + if (c->is_running(c)) { + if (my_args.list) + printf("%s\n", c->name); + else { + if (!c->stop(c)) + fprintf(stderr, "Error killing container: %s\n", c->name); + } } } - } - else if (my_args.reboot) { - /* Reboot the container */ - if (c->is_running(c)) { - if (my_args.list) - printf("%s %d\n", c->name, - get_config_integer(c, "lxc.start.delay")); - else { - if (!c->reboot(c)) - fprintf(stderr, "Error rebooting container: %s\n", c->name); - else - sleep(get_config_integer(c, "lxc.start.delay")); + else if (my_args.reboot) { + /* Reboot the container */ + if (c->is_running(c)) { + if (my_args.list) + printf("%s %d\n", c->name, + get_config_integer(c, "lxc.start.delay")); + else { + if (!c->reboot(c)) + fprintf(stderr, "Error rebooting container: %s\n", c->name); + else + sleep(get_config_integer(c, "lxc.start.delay")); + } } } - } - else { - /* Start the container */ - if (!c->is_running(c)) { - if (my_args.list) - printf("%s %d\n", c->name, - get_config_integer(c, "lxc.start.delay")); - else { - if (!c->start(c, 0, default_start_args)) - fprintf(stderr, "Error starting container: %s\n", c->name); - else - sleep(get_config_integer(c, "lxc.start.delay")); + else { + /* Start the container */ + if (!c->is_running(c)) { + if (my_args.list) + printf("%s %d\n", c->name, + get_config_integer(c, "lxc.start.delay")); + else { + if (!c->start(c, 0, default_start_args)) + fprintf(stderr, "Error starting container: %s\n", c->name); + else + sleep(get_config_integer(c, "lxc.start.delay")); + } } } + + /* + * If we get this far and we haven't hit any skip "continue" + * then we're done with this container... We can dump any + * c_groups_list and the container itself. + */ + if ( lxc_container_put(c) > 0 ) { + containers[i] = NULL; + } + if ( c_groups_lists && c_groups_lists[i] ) { + toss_list(c_groups_lists[i]); + c_groups_lists[i] = NULL; + } } - - lxc_container_put(c); } - if (cmd_groups_list) { - lxc_list_for_each_safe(it, cmd_groups_list, next) { - lxc_list_del(it); - free(it->elem); - free(it); + /* clean up any lingering detritus */ + for (i = 0; i < count; i++) { + if ( containers[i] ) { + lxc_container_put(containers[i]); } - free(cmd_groups_list); + if ( c_groups_lists && c_groups_lists[i] ) { + toss_list(c_groups_lists[i]); + } + } + + if ( c_groups_lists ) + free(c_groups_lists); + + if ( cmd_groups_list ) { + toss_list( cmd_groups_list ); } free(containers);