From: Dariusz Michaluk Date: Tue, 5 May 2015 12:58:46 +0000 (+0200) Subject: Imported Upstream version 1.1.2 X-Git-Tag: upstream/1.1.2^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca94592c0119e4b41c9ff070decbf59e29978037;p=toolchains%2Flxc.git Imported Upstream version 1.1.2 --- diff --git a/README b/README index 77572b3..3e2a963 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ What is lxc: The linux containers, lxc, aims to use these new functionalities to pro- vide a userspace container object which provides full resource isolation - and resource control for an applications or a system. + and resource control for an application or a system. The first objective of this project is to make the life easier for the ker- nel developers involved in the containers project and especially to con- diff --git a/config/init/systemd/Makefile.in b/config/init/systemd/Makefile.in index 9bf34d6..4534960 100644 --- a/config/init/systemd/Makefile.in +++ b/config/init/systemd/Makefile.in @@ -461,8 +461,8 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -@INIT_SCRIPT_SYSTEMD_FALSE@uninstall-local: @INIT_SCRIPT_SYSTEMD_FALSE@install-data-local: +@INIT_SCRIPT_SYSTEMD_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic mostlyclean-am diff --git a/config/templates/gentoo.common.conf.in b/config/templates/gentoo.common.conf.in index ca3ffc1..49cd411 100644 --- a/config/templates/gentoo.common.conf.in +++ b/config/templates/gentoo.common.conf.in @@ -21,3 +21,7 @@ lxc.cgroup.devices.allow = c 10:232 rwm ## To use loop devices, copy the following line to the container's ## configuration file (uncommented). #lxc.cgroup.devices.allow = b 7:* rwm + +# /dev/shm needs to be mounted as tmpfs. It's needed by python (bug #496328) +# and possibly other packages. +lxc.mount.entry = none dev/shm tmpfs rw,nosuid,nodev,create=dir diff --git a/configure b/configure index cacbc98..83bcc30 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for lxc 1.1.1. +# Generated by GNU Autoconf 2.69 for lxc 1.1.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='lxc' PACKAGE_TARNAME='lxc' -PACKAGE_VERSION='1.1.1' -PACKAGE_STRING='lxc 1.1.1' +PACKAGE_VERSION='1.1.2' +PACKAGE_STRING='lxc 1.1.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1435,7 +1435,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lxc 1.1.1 to adapt to many kinds of systems. +\`configure' configures lxc 1.1.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1505,7 +1505,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lxc 1.1.1:";; + short | recursive ) echo "Configuration of lxc 1.1.2:";; esac cat <<\_ACEOF @@ -1665,7 +1665,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lxc configure 1.1.1 +lxc configure 1.1.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2130,7 +2130,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lxc $as_me 1.1.1, which was +It was created by lxc $as_me 1.1.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2601,7 +2601,7 @@ $as_echo "no" >&6; } fi fi -LXC_VERSION_BASE=1.1.1 +LXC_VERSION_BASE=1.1.2 @@ -2609,9 +2609,9 @@ LXC_VERSION_MAJOR=1 LXC_VERSION_MINOR=1 -LXC_VERSION_MICRO=1 +LXC_VERSION_MICRO=2 -LXC_VERSION=1.1.1 +LXC_VERSION=1.1.2 @@ -3132,7 +3132,7 @@ fi # Define the identity of the package. PACKAGE='lxc' - VERSION='1.1.1' + VERSION='1.1.2' cat >>confdefs.h <<_ACEOF @@ -9874,7 +9874,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lxc $as_me 1.1.1, which was +This file was extended by lxc $as_me 1.1.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9944,7 +9944,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -lxc config.status 1.1.1 +lxc config.status 1.1.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 0190d8c..574b2cd 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ m4_define([lxc_version_major], 1) m4_define([lxc_version_minor], 1) -m4_define([lxc_version_micro], 1) +m4_define([lxc_version_micro], 2) m4_define([lxc_version_beta], []) m4_define([lxc_version_base], [lxc_version_major.lxc_version_minor.lxc_version_micro]) diff --git a/doc/ja/lxc-start-ephemeral.sgml.in b/doc/ja/lxc-start-ephemeral.sgml.in index eca2a8b..3f79c74 100644 --- a/doc/ja/lxc-start-ephemeral.sgml.in +++ b/doc/ja/lxc-start-ephemeral.sgml.in @@ -59,6 +59,7 @@ by KATOH Yasufumi --bdir --user --key + --storage-type --union-type --keep-data COMMAND @@ -171,6 +172,20 @@ by KATOH Yasufumi + + + + + + コンテナが使うストレージのタイプ。tmpfs か dir を指定できます。 + + + + + + @@ -209,10 +224,12 @@ by KATOH Yasufumi - 即座に指定したコマンドをコンテナ内で実行します。現時点では (attach ではなく) ssh を使用します。そしてデーモンモードと両方を指定することはできません。 + 即座に指定したコマンドをコンテナ内で実行します。 + コマンドを実行する際、カーネルがサポートしている場合は lxc-start-ephemeral は attach を使います。 + カーネルがサポートしていない場合は ssh を使います。 diff --git a/doc/lxc-start-ephemeral.sgml.in b/doc/lxc-start-ephemeral.sgml.in index d37ecf5..6f3a325 100644 --- a/doc/lxc-start-ephemeral.sgml.in +++ b/doc/lxc-start-ephemeral.sgml.in @@ -53,6 +53,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA --bdir --user --key + --storage-type --union-type --keep-data COMMAND @@ -141,6 +142,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + + + Specify the type of storage used by the container. Valid types are tmpfs or dir. + + + + + + @@ -171,8 +183,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Immediately run the provided command in the container. - This currently uses ssh (not attach) and is incompatible - with daemon mode. + This uses attach if the kernel supports it, otherwise uses ssh. + This is incompatible with daemon mode. diff --git a/lxc.spec b/lxc.spec index 15c7f32..75d2365 100644 --- a/lxc.spec +++ b/lxc.spec @@ -60,7 +60,7 @@ BuildRequires: systemd %endif Name: lxc -Version: 1.1.1 +Version: 1.1.2 Release: %{?beta_rel:0.1.%{beta_rel}}%{?!beta_rel:%{norm_rel}}%{?dist} URL: http://linuxcontainers.org Source: http://linuxcontainers.org/downloads/%{name}-%{version}%{?beta_dot}.tar.gz diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index b1e56b9..8b79c40 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -248,6 +248,7 @@ endif init_lxc_static_LDFLAGS = -static init_lxc_static_LDADD = @CAP_LIBS@ +init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF endif install-exec-local: install-soPROGRAMS diff --git a/src/lxc/Makefile.in b/src/lxc/Makefile.in index 74052ef..c8ca0f0 100644 --- a/src/lxc/Makefile.in +++ b/src/lxc/Makefile.in @@ -148,14 +148,17 @@ init_lxc_DEPENDENCIES = liblxc.so am__init_lxc_static_SOURCES_DIST = lxc_init.c error.c log.c utils.c \ caps.c ../include/getline.c am__dirstamp = $(am__leading_dot)dirstamp -@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@@HAVE_STATIC_LIBCAP_TRUE@am__objects_1 = ../include/getline.$(OBJEXT) +@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@@HAVE_STATIC_LIBCAP_TRUE@am__objects_1 = ../include/init_lxc_static-getline.$(OBJEXT) @HAVE_STATIC_LIBCAP_TRUE@am_init_lxc_static_OBJECTS = \ -@HAVE_STATIC_LIBCAP_TRUE@ lxc_init.$(OBJEXT) error.$(OBJEXT) \ -@HAVE_STATIC_LIBCAP_TRUE@ log.$(OBJEXT) utils.$(OBJEXT) \ -@HAVE_STATIC_LIBCAP_TRUE@ caps.$(OBJEXT) $(am__objects_1) +@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-lxc_init.$(OBJEXT) \ +@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-error.$(OBJEXT) \ +@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-log.$(OBJEXT) \ +@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-utils.$(OBJEXT) \ +@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-caps.$(OBJEXT) \ +@HAVE_STATIC_LIBCAP_TRUE@ $(am__objects_1) init_lxc_static_OBJECTS = $(am_init_lxc_static_OBJECTS) init_lxc_static_DEPENDENCIES = -init_lxc_static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ +init_lxc_static_LINK = $(CCLD) $(init_lxc_static_CFLAGS) $(CFLAGS) \ $(init_lxc_static_LDFLAGS) $(LDFLAGS) -o $@ am__liblxc_so_SOURCES_DIST = arguments.c arguments.h bdev.c bdev.h \ lxc-btrfs.h commands.c commands.h start.c start.h execute.c \ @@ -670,6 +673,7 @@ lxc_checkpoint_SOURCES = lxc_checkpoint.c @HAVE_STATIC_LIBCAP_TRUE@ log.c utils.c caps.c $(am__append_20) @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDFLAGS = -static @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDADD = @CAP_LIBS@ +@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF all: all-am .SUFFIXES: @@ -892,7 +896,8 @@ init.lxc$(EXEEXT): $(init_lxc_OBJECTS) $(init_lxc_DEPENDENCIES) $(EXTRA_init_lxc ../include/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../include/$(DEPDIR) @: > ../include/$(DEPDIR)/$(am__dirstamp) -../include/getline.$(OBJEXT): ../include/$(am__dirstamp) \ +../include/init_lxc_static-getline.$(OBJEXT): \ + ../include/$(am__dirstamp) \ ../include/$(DEPDIR)/$(am__dirstamp) init.lxc.static$(EXEEXT): $(init_lxc_static_OBJECTS) $(init_lxc_static_DEPENDENCIES) $(EXTRA_init_lxc_static_DEPENDENCIES) @@ -1064,13 +1069,16 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/getline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/init_lxc_static-getline.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/liblxc_so-getline.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/liblxc_so-ifaddrs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/liblxc_so-lxcmntent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/liblxc_so-openpty.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/caps.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-caps.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-lxc_init.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-af_unix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-arguments.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-attach.Po@am__quote@ @@ -1103,7 +1111,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-state.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-sync.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-utils.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_attach.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_autostart.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_cgroup.Po@am__quote@ @@ -1130,7 +1137,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_usernsexec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_wait.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lsm/$(DEPDIR)/liblxc_so-apparmor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lsm/$(DEPDIR)/liblxc_so-lsm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lsm/$(DEPDIR)/liblxc_so-nop.Po@am__quote@ @@ -1152,6 +1158,90 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +init_lxc_static-lxc_init.o: lxc_init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-lxc_init.o -MD -MP -MF $(DEPDIR)/init_lxc_static-lxc_init.Tpo -c -o init_lxc_static-lxc_init.o `test -f 'lxc_init.c' || echo '$(srcdir)/'`lxc_init.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-lxc_init.Tpo $(DEPDIR)/init_lxc_static-lxc_init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lxc_init.c' object='init_lxc_static-lxc_init.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-lxc_init.o `test -f 'lxc_init.c' || echo '$(srcdir)/'`lxc_init.c + +init_lxc_static-lxc_init.obj: lxc_init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-lxc_init.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-lxc_init.Tpo -c -o init_lxc_static-lxc_init.obj `if test -f 'lxc_init.c'; then $(CYGPATH_W) 'lxc_init.c'; else $(CYGPATH_W) '$(srcdir)/lxc_init.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-lxc_init.Tpo $(DEPDIR)/init_lxc_static-lxc_init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lxc_init.c' object='init_lxc_static-lxc_init.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-lxc_init.obj `if test -f 'lxc_init.c'; then $(CYGPATH_W) 'lxc_init.c'; else $(CYGPATH_W) '$(srcdir)/lxc_init.c'; fi` + +init_lxc_static-error.o: error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-error.o -MD -MP -MF $(DEPDIR)/init_lxc_static-error.Tpo -c -o init_lxc_static-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-error.Tpo $(DEPDIR)/init_lxc_static-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='init_lxc_static-error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c + +init_lxc_static-error.obj: error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-error.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-error.Tpo -c -o init_lxc_static-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-error.Tpo $(DEPDIR)/init_lxc_static-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='init_lxc_static-error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` + +init_lxc_static-log.o: log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-log.o -MD -MP -MF $(DEPDIR)/init_lxc_static-log.Tpo -c -o init_lxc_static-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-log.Tpo $(DEPDIR)/init_lxc_static-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='init_lxc_static-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c + +init_lxc_static-log.obj: log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-log.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-log.Tpo -c -o init_lxc_static-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-log.Tpo $(DEPDIR)/init_lxc_static-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='init_lxc_static-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` + +init_lxc_static-utils.o: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-utils.o -MD -MP -MF $(DEPDIR)/init_lxc_static-utils.Tpo -c -o init_lxc_static-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-utils.Tpo $(DEPDIR)/init_lxc_static-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='init_lxc_static-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c + +init_lxc_static-utils.obj: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-utils.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-utils.Tpo -c -o init_lxc_static-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-utils.Tpo $(DEPDIR)/init_lxc_static-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='init_lxc_static-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` + +init_lxc_static-caps.o: caps.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-caps.o -MD -MP -MF $(DEPDIR)/init_lxc_static-caps.Tpo -c -o init_lxc_static-caps.o `test -f 'caps.c' || echo '$(srcdir)/'`caps.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-caps.Tpo $(DEPDIR)/init_lxc_static-caps.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='caps.c' object='init_lxc_static-caps.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-caps.o `test -f 'caps.c' || echo '$(srcdir)/'`caps.c + +init_lxc_static-caps.obj: caps.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-caps.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-caps.Tpo -c -o init_lxc_static-caps.obj `if test -f 'caps.c'; then $(CYGPATH_W) 'caps.c'; else $(CYGPATH_W) '$(srcdir)/caps.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-caps.Tpo $(DEPDIR)/init_lxc_static-caps.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='caps.c' object='init_lxc_static-caps.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-caps.obj `if test -f 'caps.c'; then $(CYGPATH_W) 'caps.c'; else $(CYGPATH_W) '$(srcdir)/caps.c'; fi` + +../include/init_lxc_static-getline.o: ../include/getline.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT ../include/init_lxc_static-getline.o -MD -MP -MF ../include/$(DEPDIR)/init_lxc_static-getline.Tpo -c -o ../include/init_lxc_static-getline.o `test -f '../include/getline.c' || echo '$(srcdir)/'`../include/getline.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../include/$(DEPDIR)/init_lxc_static-getline.Tpo ../include/$(DEPDIR)/init_lxc_static-getline.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../include/getline.c' object='../include/init_lxc_static-getline.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o ../include/init_lxc_static-getline.o `test -f '../include/getline.c' || echo '$(srcdir)/'`../include/getline.c + +../include/init_lxc_static-getline.obj: ../include/getline.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT ../include/init_lxc_static-getline.obj -MD -MP -MF ../include/$(DEPDIR)/init_lxc_static-getline.Tpo -c -o ../include/init_lxc_static-getline.obj `if test -f '../include/getline.c'; then $(CYGPATH_W) '../include/getline.c'; else $(CYGPATH_W) '$(srcdir)/../include/getline.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../include/$(DEPDIR)/init_lxc_static-getline.Tpo ../include/$(DEPDIR)/init_lxc_static-getline.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../include/getline.c' object='../include/init_lxc_static-getline.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o ../include/init_lxc_static-getline.obj `if test -f '../include/getline.c'; then $(CYGPATH_W) '../include/getline.c'; else $(CYGPATH_W) '$(srcdir)/../include/getline.c'; fi` + liblxc_so-arguments.o: arguments.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-arguments.o -MD -MP -MF $(DEPDIR)/liblxc_so-arguments.Tpo -c -o liblxc_so-arguments.o `test -f 'arguments.c' || echo '$(srcdir)/'`arguments.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-arguments.Tpo $(DEPDIR)/liblxc_so-arguments.Po diff --git a/src/lxc/attach.c b/src/lxc/attach.c index faa90fc..69dafd4 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -985,7 +985,7 @@ static int attach_child_main(void* data) new_gid = options->gid; /* setup the control tty */ - if (options->stdin_fd) { + if (options->stdin_fd && isatty(options->stdin_fd)) { if (setsid() < 0) { SYSERROR("unable to setsid"); shutdown(ipc_socket, SHUT_RDWR); diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c index 20325fa..11a5925 100644 --- a/src/lxc/cgfs.c +++ b/src/lxc/cgfs.c @@ -2403,4 +2403,5 @@ static struct cgroup_ops cgfs_ops = { .chown = NULL, .mount_cgroup = cgroupfs_mount_cgroup, .nrtasks = cgfs_nrtasks, + .driver = CGFS, }; diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c index 0932d96..fe8913e 100644 --- a/src/lxc/cgmanager.c +++ b/src/lxc/cgmanager.c @@ -246,11 +246,12 @@ static void check_supports_multiple_controllers(pid_t pid) } if (strcmp(prevpath, colon) != 0) { cgm_all_controllers_same = false; - fclose(f); - return; + break; } } + fclose(f); + free(line); } static int send_creds(int sock, int rpid, int ruid, int rgid) @@ -1396,5 +1397,6 @@ static struct cgroup_ops cgmanager_ops = { .mount_cgroup = cgm_mount_cgroup, .nrtasks = cgm_get_nrtasks, .disconnect = NULL, + .driver = CGMANAGER, }; #endif diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c index a413832..2362ad8 100644 --- a/src/lxc/cgroup.c +++ b/src/lxc/cgroup.c @@ -189,3 +189,8 @@ void cgroup_disconnect(void) if (ops && ops->disconnect) ops->disconnect(); } + +cgroup_driver_t cgroup_driver(void) +{ + return ops->driver; +} diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h index 281f404..6706939 100644 --- a/src/lxc/cgroup.h +++ b/src/lxc/cgroup.h @@ -32,6 +32,11 @@ struct lxc_handler; struct lxc_conf; struct lxc_list; +typedef enum { + CGFS, + CGMANAGER, +} cgroup_driver_t; + struct cgroup_ops { const char *name; @@ -51,6 +56,7 @@ struct cgroup_ops { bool (*mount_cgroup)(void *hdata, const char *root, int type); int (*nrtasks)(void *hdata); void (*disconnect)(void); + cgroup_driver_t driver; }; extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid); @@ -72,5 +78,6 @@ extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *su extern const char *cgroup_canonical_path(struct lxc_handler *handler); extern bool cgroup_unfreeze(struct lxc_handler *handler); extern void cgroup_disconnect(void); +extern cgroup_driver_t cgroup_driver(void); #endif diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 2868708..4249c6c 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -178,6 +178,17 @@ struct caps_opt { int value; }; +/* + * The lxc_conf of the container currently being worked on in an + * API call + * This is used in the error calls + */ +#ifdef HAVE_TLS +__thread struct lxc_conf *current_config; +#else +struct lxc_conf *current_config; +#endif + /* Declare this here, since we don't want to reshuffle the whole file. */ static int in_caplist(int cap, struct lxc_list *caps); @@ -2040,18 +2051,16 @@ static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab, return ret; } -static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount, - const char *lxc_name) +FILE *write_mount_file(struct lxc_list *mount) { FILE *file; struct lxc_list *iterator; char *mount_entry; - int ret; file = tmpfile(); if (!file) { ERROR("tmpfile error: %m"); - return -1; + return NULL; } lxc_list_for_each(iterator, mount) { @@ -2060,6 +2069,18 @@ static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list } rewind(file); + return file; +} + +static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount, + const char *lxc_name) +{ + FILE *file; + int ret; + + file = write_mount_file(mount); + if (!file) + return -1; ret = mount_file_entries(rootfs, file, lxc_name); @@ -2563,6 +2584,7 @@ struct lxc_conf *lxc_conf_init(void) return NULL; } new->kmsg = 0; + new->logfd = -1; lxc_list_init(&new->cgroup); lxc_list_init(&new->network); lxc_list_init(&new->mount_list); @@ -4230,6 +4252,8 @@ void lxc_conf_free(struct lxc_conf *conf) free(conf->rootfs.path); free(conf->rootfs.pivot); free(conf->logfile); + if (conf->logfd != -1) + close(conf->logfd); free(conf->utsname); free(conf->ttydir); free(conf->fstab); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index afa5517..f3f8fd5 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -25,6 +25,7 @@ #include "config.h" +#include #include #include #include @@ -334,6 +335,7 @@ struct lxc_conf { // store the config file specified values here. char *logfile; // the logfile as specifed in config int loglevel; // loglevel as specifed in config (if any) + int logfd; int inherit_ns_fd[LXC_NS_MAX]; @@ -363,6 +365,12 @@ struct lxc_conf { char *init_cmd; }; +#ifdef HAVE_TLS +extern __thread struct lxc_conf *current_config; +#else +extern struct lxc_conf *current_config; +#endif + int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, const char *lxcpath, char *argv[]); @@ -421,4 +429,5 @@ extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); void remount_all_slave(void); extern void suggest_default_idmap(void); +FILE *write_mount_file(struct lxc_list *mount); #endif diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 740487b..8189351 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -1169,15 +1169,15 @@ static int config_lsm_se_context(const char *key, const char *value, } static int config_logfile(const char *key, const char *value, - struct lxc_conf *lxc_conf) + struct lxc_conf *c) { int ret; // store these values in the lxc_conf, and then try to set for // actual current logging. - ret = config_path_item(&lxc_conf->logfile, value); + ret = config_path_item(&c->logfile, value); if (ret == 0) - ret = lxc_log_set_file(lxc_conf->logfile); + ret = lxc_log_set_file(&c->logfd, c->logfile); return ret; } @@ -1196,7 +1196,7 @@ static int config_loglevel(const char *key, const char *value, // store these values in the lxc_conf, and then try to set for // actual current logging. lxc_conf->loglevel = newlevel; - return lxc_log_set_level(newlevel); + return lxc_log_set_level(&lxc_conf->loglevel, newlevel); } static int config_autodev(const char *key, const char *value, @@ -2367,9 +2367,9 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, else if (strcmp(key, "lxc.se_context") == 0) v = c->lsm_se_context; else if (strcmp(key, "lxc.logfile") == 0) - v = lxc_log_get_file(); + v = c->logfile; else if (strcmp(key, "lxc.loglevel") == 0) - v = lxc_log_priority_to_string(lxc_log_get_level()); + v = lxc_log_priority_to_string(c->loglevel); else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info return lxc_get_cgroup_entry(c, retv, inlen, "all"); else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info diff --git a/src/lxc/list.h b/src/lxc/list.h index 0882da0..f16af54 100644 --- a/src/lxc/list.h +++ b/src/lxc/list.h @@ -99,4 +99,15 @@ static inline void lxc_list_del(struct lxc_list *list) prev->next = next; } +static inline int lxc_list_len(struct lxc_list *list) +{ + int i = 0; + struct lxc_list *iter; + lxc_list_for_each(iter, list) { + i++; + } + + return i; +} + #endif diff --git a/src/lxc/log.c b/src/lxc/log.c index 6633e62..04ba2cc 100644 --- a/src/lxc/log.c +++ b/src/lxc/log.c @@ -27,6 +27,7 @@ #include #include #include +#include #define __USE_GNU /* for *_CLOEXEC */ @@ -40,27 +41,44 @@ #define LXC_LOG_PREFIX_SIZE 32 #define LXC_LOG_BUFFER_SIZE 512 -#ifdef HAVE_TLS -__thread int lxc_log_fd = -1; -static __thread char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc"; -static __thread char *log_fname = NULL; -/* command line values for logfile or logpriority should always override - * values from the configuration file or defaults - */ -static __thread int lxc_logfile_specified = 0; -static __thread int lxc_loglevel_specified = 0; -static __thread int lxc_quiet_specified = 0; -#else +static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; +static void lock_mutex(pthread_mutex_t *l) +{ + int ret; + + if ((ret = pthread_mutex_lock(l)) != 0) { + fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret)); + exit(1); + } +} + +static void unlock_mutex(pthread_mutex_t *l) +{ + int ret; + + if ((ret = pthread_mutex_unlock(l)) != 0) { + fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret)); + exit(1); + } +} + +void log_lock(void) +{ + lock_mutex(&log_mutex); +} + +void log_unlock(void) +{ + unlock_mutex(&log_mutex); +} + int lxc_log_fd = -1; +int lxc_quiet_specified; +int lxc_log_use_global_fd; +static int lxc_loglevel_specified; + static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc"; static char *log_fname = NULL; -static int lxc_quiet_specified = 0; -/* command line values for logfile or logpriority should always override - * values from the configuration file or defaults - */ -static int lxc_logfile_specified = 0; -static int lxc_loglevel_specified = 0; -#endif lxc_log_define(lxc_log, lxc); @@ -85,8 +103,17 @@ static int log_append_logfile(const struct lxc_log_appender *appender, char buffer[LXC_LOG_BUFFER_SIZE]; int n; int ms; + int fd_to_use = -1; - if (lxc_log_fd == -1) +#ifndef NO_LXC_CONF + if (!lxc_log_use_global_fd && current_config) + fd_to_use = current_config->logfd; +#endif + + if (fd_to_use == -1) + fd_to_use = lxc_log_fd; + + if (fd_to_use == -1) return 0; ms = event->timestamp.tv_usec / 1000; @@ -111,7 +138,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender, buffer[n] = '\n'; - return write(lxc_log_fd, buffer, n + 1); + return write(fd_to_use, buffer, n + 1); } static struct lxc_log_appender log_appender_stderr = { @@ -136,7 +163,7 @@ static struct lxc_log_category log_root = { struct lxc_log_category lxc_log_category_lxc = { .name = "lxc", .priority = LXC_LOG_PRIORITY_ERROR, - .appender = &log_appender_stderr, + .appender = &log_appender_logfile, .parent = &log_root }; @@ -305,6 +332,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d return ret; } +/* + * lxc_log_init: + * Called from lxc front-end programs (like lxc-create, lxc-start) to + * initalize the log defaults. + */ extern int lxc_log_init(const char *name, const char *file, const char *priority, const char *prefix, int quiet, const char *lxcpath) @@ -320,10 +352,12 @@ extern int lxc_log_init(const char *name, const char *file, if (priority) lxc_priority = lxc_log_priority_to_int(priority); - lxc_log_category_lxc.priority = lxc_priority; + if (!lxc_loglevel_specified) { + lxc_log_category_lxc.priority = lxc_priority; + lxc_loglevel_specified = 1; + } if (!lxc_quiet_specified) { - lxc_log_category_lxc.appender = &log_appender_logfile; if (!quiet) lxc_log_category_lxc.appender->next = &log_appender_stderr; } @@ -335,6 +369,7 @@ extern int lxc_log_init(const char *name, const char *file, if (strcmp(file, "none") == 0) return 0; ret = __lxc_log_set_file(file, 1); + lxc_log_use_global_fd = 1; } else { /* if no name was specified, there nothing to do */ if (!name) @@ -385,15 +420,13 @@ extern void lxc_log_close(void) * happens after processing command line arguments, which override the .conf * settings. So only set the level if previously unset. */ -extern int lxc_log_set_level(int level) +extern int lxc_log_set_level(int *dest, int level) { - if (lxc_loglevel_specified) - return 0; if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) { ERROR("invalid log priority %d", level); return -1; } - lxc_log_category_lxc.priority = level; + *dest = level; return 0; } @@ -415,11 +448,23 @@ extern bool lxc_log_has_valid_level(void) * happens after processing command line arguments, which override the .conf * settings. So only set the file if previously unset. */ -extern int lxc_log_set_file(const char *fname) +extern int lxc_log_set_file(int *fd, const char *fname) { - if (lxc_logfile_specified) - return 0; - return __lxc_log_set_file(fname, 0); + if (*fd != -1) { + close(*fd); + *fd = -1; + } + + if (build_dir(fname)) { + ERROR("failed to create dir for log file \"%s\" : %s", fname, + strerror(errno)); + return -1; + } + + *fd = log_open(fname); + if (*fd == -1) + return -errno; + return 0; } extern const char *lxc_log_get_file(void) @@ -440,11 +485,6 @@ extern const char *lxc_log_get_prefix(void) extern void lxc_log_options_no_override() { - if (lxc_log_get_file()) - lxc_logfile_specified = 1; - - if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET) - lxc_loglevel_specified = 1; - lxc_quiet_specified = 1; + lxc_loglevel_specified = 1; } diff --git a/src/lxc/log.h b/src/lxc/log.h index b47f120..76bd4df 100644 --- a/src/lxc/log.h +++ b/src/lxc/log.h @@ -33,6 +33,8 @@ #include #include +#include "conf.h" + #ifndef O_CLOEXEC #define O_CLOEXEC 02000000 #endif @@ -104,6 +106,10 @@ struct lxc_log_category { const struct lxc_log_category *parent; }; +#ifndef NO_LXC_CONF +extern int lxc_log_use_global_fd; +#endif + /* * Returns true if the chained priority is equal to or higher than * given priority. @@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category, category->parent) category = category->parent; - return priority >= category->priority; + int cmp_prio = category->priority; +#ifndef NO_LXC_CONF + if (!lxc_log_use_global_fd && current_config && + current_config->loglevel != LXC_LOG_PRIORITY_NOTSET) + cmp_prio = current_config->loglevel; +#endif + + return priority >= cmp_prio; } /* @@ -294,18 +307,14 @@ ATTR_UNUSED static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo, \ ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \ } while (0) -#ifdef HAVE_TLS -extern __thread int lxc_log_fd; -#else extern int lxc_log_fd; -#endif extern int lxc_log_init(const char *name, const char *file, const char *priority, const char *prefix, int quiet, const char *lxcpath); -extern int lxc_log_set_file(const char *fname); -extern int lxc_log_set_level(int level); +extern int lxc_log_set_file(int *fd, const char *fname); +extern int lxc_log_set_level(int *dest, int level); extern void lxc_log_set_prefix(const char *prefix); extern const char *lxc_log_get_file(void); extern int lxc_log_get_level(void); diff --git a/src/lxc/lxc-start-ephemeral.in b/src/lxc/lxc-start-ephemeral.in index b049f80..7bf336e 100644 --- a/src/lxc/lxc-start-ephemeral.in +++ b/src/lxc/lxc-start-ephemeral.in @@ -240,17 +240,15 @@ LXC_NAME="%s" count = 0 for entry in overlay_dirs: tmpdir = "%s/tmpfs" % dest_path + fd.write("mkdir -p %s\n" % (tmpdir)) + if args.storage_type == "tmpfs": + fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (tmpdir)) deltdir = "%s/delta%s" % (tmpdir, count) workdir = "%s/work%s" % (tmpdir, count) fd.write("mkdir -p %s %s\n" % (deltdir, entry[1])) if have_new_overlay: fd.write("mkdir -p %s\n" % workdir) - if args.storage_type == "tmpfs": - fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (tmpdir)) - fd.write("mkdir %s\n" % deltdir) - fd.write("mkdir %s\n" % workdir) - fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" % (entry[0], deltdir)) fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" % diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c index cfa08fc..2e76c2e 100644 --- a/src/lxc/lxc_checkpoint.c +++ b/src/lxc/lxc_checkpoint.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include @@ -27,6 +29,7 @@ #include "config.h" #include "lxc.h" #include "arguments.h" +#include "utils.h" static char *checkpoint_dir = NULL; static bool stop = false; @@ -139,36 +142,53 @@ bool checkpoint(struct lxc_container *c) return true; } -bool restore(struct lxc_container *c) +bool restore_finalize(struct lxc_container *c) { - pid_t pid = 0; - bool ret = true; + bool ret = c->restore(c, checkpoint_dir, verbose); + if (!ret) { + fprintf(stderr, "Restoring %s failed.\n", my_args.name); + } + lxc_container_put(c); + return ret; +} + +bool restore(struct lxc_container *c) +{ if (c->is_running(c)) { fprintf(stderr, "%s is running, not restoring.\n", my_args.name); lxc_container_put(c); return false; } - if (my_args.daemonize) + if (my_args.daemonize) { + pid_t pid; + pid = fork(); + if (pid < 0) { + perror("fork"); + return false; + } - if (pid == 0) { - if (my_args.daemonize) { + if (pid == 0) { close(0); close(1); - } - ret = c->restore(c, checkpoint_dir, verbose); - - if (!ret) { - fprintf(stderr, "Restoring %s failed.\n", my_args.name); + exit(!restore_finalize(c)); + } else { + return wait_for_pid(pid) == 0; } - } + } else { + int status; - lxc_container_put(c); + if (!restore_finalize(c)) + return false; - return ret; + if (waitpid(-1, &status, 0) < 0) + return false; + + return WIFEXITED(status) && WEXITSTATUS(status) == 0; + } } int main(int argc, char *argv[]) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index e02ee93..522d652 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,12 @@ #include <../include/ifaddrs.h> #endif +#if IS_BIONIC +#include <../include/lxcmntent.h> +#else +#include +#endif + #define MAX_BUFFER 4096 #define NOT_SUPPORTED_ERROR "the requested function %s is not currently supported with unprivileged containers" @@ -82,9 +89,17 @@ return -1; } #endif - lxc_log_define(lxc_container, lxc); +static bool do_lxcapi_destroy(struct lxc_container *c); +static const char *lxcapi_get_config_path(struct lxc_container *c); +#define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c) +static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v); +static bool container_destroy(struct lxc_container *c); +static bool get_snappath_dir(struct lxc_container *c, char *snappath); +static bool lxcapi_snapshot_destroy_all(struct lxc_container *c); +static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file); + static bool config_file_exists(const char *lxcpath, const char *cname) { /* $lxcpath + '/' + $cname + '/config' + \0 */ @@ -301,7 +316,7 @@ int lxc_container_put(struct lxc_container *c) return 0; } -static bool lxcapi_is_defined(struct lxc_container *c) +static bool do_lxcapi_is_defined(struct lxc_container *c) { struct stat statbuf; bool ret = false; @@ -324,7 +339,53 @@ out: return ret; } -static const char *lxcapi_state(struct lxc_container *c) +#define WRAP_API(rettype, fnname) \ +static rettype fnname(struct lxc_container *c) \ +{ \ + rettype ret; \ + struct lxc_conf *old = current_config; \ + current_config = c ? c->lxc_conf : NULL; \ + ret = do_##fnname(c); \ + current_config = old; \ + return ret; \ +} + +#define WRAP_API_1(rettype, fnname, t1) \ +static rettype fnname(struct lxc_container *c, t1 a1) \ +{ \ + rettype ret; \ + struct lxc_conf *old = current_config; \ + current_config = c ? c->lxc_conf : NULL; \ + ret = do_##fnname(c, a1); \ + current_config = old; \ + return ret; \ +} + +#define WRAP_API_2(rettype, fnname, t1, t2) \ +static rettype fnname(struct lxc_container *c, t1 a1, t2 a2) \ +{ \ + rettype ret; \ + struct lxc_conf *old = current_config; \ + current_config = c ? c->lxc_conf : NULL; \ + ret = do_##fnname(c, a1, a2); \ + current_config = old; \ + return ret; \ +} + +#define WRAP_API_3(rettype, fnname, t1, t2, t3) \ +static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3) \ +{ \ + rettype ret; \ + struct lxc_conf *old = current_config; \ + current_config = c ? c->lxc_conf : NULL; \ + ret = do_##fnname(c, a1, a2, a3); \ + current_config = old; \ + return ret; \ +} + +WRAP_API(bool, lxcapi_is_defined) + +static const char *do_lxcapi_state(struct lxc_container *c) { lxc_state_t s; @@ -334,6 +395,8 @@ static const char *lxcapi_state(struct lxc_container *c) return lxc_state2str(s); } +WRAP_API(const char *, lxcapi_state) + static bool is_stopped(struct lxc_container *c) { lxc_state_t s; @@ -341,19 +404,21 @@ static bool is_stopped(struct lxc_container *c) return (s == STOPPED); } -static bool lxcapi_is_running(struct lxc_container *c) +static bool do_lxcapi_is_running(struct lxc_container *c) { const char *s; if (!c) return false; - s = lxcapi_state(c); + s = do_lxcapi_state(c); if (!s || strcmp(s, "STOPPED") == 0) return false; return true; } -static bool lxcapi_freeze(struct lxc_container *c) +WRAP_API(bool, lxcapi_is_running) + +static bool do_lxcapi_freeze(struct lxc_container *c) { int ret; if (!c) @@ -365,7 +430,9 @@ static bool lxcapi_freeze(struct lxc_container *c) return true; } -static bool lxcapi_unfreeze(struct lxc_container *c) +WRAP_API(bool, lxcapi_freeze) + +static bool do_lxcapi_unfreeze(struct lxc_container *c) { int ret; if (!c) @@ -377,7 +444,9 @@ static bool lxcapi_unfreeze(struct lxc_container *c) return true; } -static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd) +WRAP_API(bool, lxcapi_unfreeze) + +static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd) { int ttyfd; if (!c) @@ -387,13 +456,20 @@ static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *maste return ttyfd; } +WRAP_API_2(int, lxcapi_console_getfd, int *, int *) + static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd, int stdoutfd, int stderrfd, int escape) { - return lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape); + int ret; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape); + current_config = old; + return ret; } -static pid_t lxcapi_init_pid(struct lxc_container *c) +static pid_t do_lxcapi_init_pid(struct lxc_container *c) { if (!c) return -1; @@ -401,6 +477,8 @@ static pid_t lxcapi_init_pid(struct lxc_container *c) return lxc_cmd_get_init_pid(c->name, c->config_path); } +WRAP_API(pid_t, lxcapi_init_pid) + static bool load_config_locked(struct lxc_container *c, const char *fname) { if (!c->lxc_conf) @@ -412,7 +490,7 @@ static bool load_config_locked(struct lxc_container *c, const char *fname) return true; } -static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file) +static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) { bool ret = false, need_disklock = false; int lret; @@ -449,7 +527,9 @@ static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file) return ret; } -static bool lxcapi_want_daemonize(struct lxc_container *c, bool state) +WRAP_API_1(bool, lxcapi_load_config, const char *) + +static bool do_lxcapi_want_daemonize(struct lxc_container *c, bool state) { if (!c || !c->lxc_conf) return false; @@ -462,7 +542,9 @@ static bool lxcapi_want_daemonize(struct lxc_container *c, bool state) return true; } -static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state) +WRAP_API_1(bool, lxcapi_want_daemonize, bool) + +static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state) { if (!c || !c->lxc_conf) return false; @@ -475,7 +557,9 @@ static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state) return true; } -static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout) +WRAP_API_1(bool, lxcapi_want_close_all_fds, bool) + +static bool do_lxcapi_wait(struct lxc_container *c, const char *state, int timeout) { int ret; @@ -486,8 +570,9 @@ static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout) return ret == 0; } +WRAP_API_2(bool, lxcapi_wait, const char *, int) -static bool wait_on_daemonized_start(struct lxc_container *c, int pid) +static bool do_wait_on_daemonized_start(struct lxc_container *c, int pid) { /* we'll probably want to make this timeout configurable? */ int timeout = 5, ret, status; @@ -499,9 +584,11 @@ static bool wait_on_daemonized_start(struct lxc_container *c, int pid) ret = waitpid(pid, &status, 0); if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) DEBUG("failed waiting for first dual-fork child"); - return lxcapi_wait(c, "RUNNING", timeout); + return do_lxcapi_wait(c, "RUNNING", timeout); } +WRAP_API_1(bool, wait_on_daemonized_start, int) + static bool am_single_threaded(void) { struct dirent dirent, *direntp; @@ -534,7 +621,7 @@ static bool am_single_threaded(void) * I can't decide if it'd be more convenient for callers if we accept '...', * or a null-terminated array (i.e. execl vs execv) */ -static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) +static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) { int ret; struct lxc_conf *conf; @@ -559,7 +646,7 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv } if (ret == 2) { ERROR("Error: %s creation was not completed", c->name); - c->destroy(c); + do_lxcapi_destroy(c); return false; } else if (ret == 1) { ERROR("Error: creation of %s is ongoing", c->name); @@ -702,6 +789,16 @@ out: return (ret == 0 ? true : false); } +static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) +{ + bool ret; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + ret = do_lxcapi_start(c, useinit, argv); + current_config = old; + return ret; +} + /* * note there MUST be an ending NULL */ @@ -715,6 +812,9 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) if (!c) return false; + struct lxc_conf *old = current_config; + current_config = c->lxc_conf; + va_start(ap, useinit); inargs = lxc_va_arg_list_to_argv(ap, 0, 1); va_end(ap); @@ -725,7 +825,7 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) } /* pass NULL if no arguments were supplied */ - bret = lxcapi_start(c, useinit, *inargs ? inargs : NULL); + bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL); out: if (inargs) { @@ -735,10 +835,11 @@ out: free(inargs); } + current_config = old; return bret; } -static bool lxcapi_stop(struct lxc_container *c) +static bool do_lxcapi_stop(struct lxc_container *c) { int ret; @@ -750,6 +851,8 @@ static bool lxcapi_stop(struct lxc_container *c) return ret == 0; } +WRAP_API(bool, lxcapi_stop) + static int do_create_container_dir(const char *path, struct lxc_conf *conf) { int ret = -1, lasterr; @@ -797,9 +900,6 @@ static bool create_container_dir(struct lxc_container *c) return ret == 0; } -static const char *lxcapi_get_config_path(struct lxc_container *c); -static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v); - /* * do_bdev_create: thin wrapper around bdev_create(). Like bdev_create(), * it returns a mounted bdev on success, NULL on error. @@ -819,7 +919,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, dest = alloca(len); ret = snprintf(dest, len, "%s", rpath); } else { - const char *lxcpath = lxcapi_get_config_path(c); + const char *lxcpath = do_lxcapi_get_config_path(c); len = strlen(c->name) + strlen(lxcpath) + 9; dest = alloca(len); ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name); @@ -833,7 +933,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, return NULL; } - lxcapi_set_config_item(c, "lxc.rootfs", bdev->src); + do_lxcapi_set_config_item(c, "lxc.rootfs", bdev->src); /* if we are not root, chown the rootfs dir to root in the * target uidmap */ @@ -1210,9 +1310,8 @@ static void lxcapi_clear_config(struct lxc_container *c) } } -static bool lxcapi_destroy(struct lxc_container *c); -static bool container_destroy(struct lxc_container *c); -static bool get_snappath_dir(struct lxc_container *c, char *snappath); +#define do_lxcapi_clear_config(c) lxcapi_clear_config(c) + /* * lxcapi_create: * create a container with the given parameters. @@ -1227,7 +1326,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath); * @argv: the arguments to pass to the template, terminated by NULL. If no * arguments, you can just pass NULL. */ -static bool lxcapi_create(struct lxc_container *c, const char *t, +static bool do_lxcapi_create(struct lxc_container *c, const char *t, const char *bdevtype, struct bdev_specs *specs, int flags, char *const argv[]) { @@ -1253,14 +1352,14 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, * an existing container. Return an error, but do NOT delete the * container. */ - if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && + if (do_lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) { ERROR("Container %s:%s already exists", c->config_path, c->name); goto free_tpath; } if (!c->lxc_conf) { - if (!c->load_config(c, lxc_global_config_value("lxc.default_config"))) { + if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) { ERROR("Error loading default configuration file %s", lxc_global_config_value("lxc.default_config")); goto free_tpath; } @@ -1280,7 +1379,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0) /* rootfs passed into configuration, but does not exist: error */ goto out; - if (lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) { + if (do_lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) { /* Rootfs already existed, user just wanted to save the * loaded configuration */ ret = true; @@ -1316,7 +1415,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, } /* save config file again to store the new rootfs location */ - if (!c->save_config(c, NULL)) { + if (!do_lxcapi_save_config(c, NULL)) { ERROR("failed to save starting configuration for %s", c->name); // parent task won't see bdev in config so we delete it bdev->ops->umount(bdev); @@ -1339,7 +1438,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, // now clear out the lxc_conf we have, reload from the created // container - lxcapi_clear_config(c); + do_lxcapi_clear_config(c); if (t) { if (!prepend_lxc_header(c->configfile, tpath, argv)) { @@ -1360,15 +1459,27 @@ free_tpath: return ret; } -static bool lxcapi_reboot(struct lxc_container *c) +static bool lxcapi_create(struct lxc_container *c, const char *t, + const char *bdevtype, struct bdev_specs *specs, int flags, + char *const argv[]) +{ + bool ret; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv); + current_config = old; + return ret; +} + +static bool do_lxcapi_reboot(struct lxc_container *c) { pid_t pid; if (!c) return false; - if (!c->is_running(c)) + if (!do_lxcapi_is_running(c)) return false; - pid = c->init_pid(c); + pid = do_lxcapi_init_pid(c); if (pid <= 0) return false; if (kill(pid, SIGINT) < 0) @@ -1377,7 +1488,9 @@ static bool lxcapi_reboot(struct lxc_container *c) } -static bool lxcapi_shutdown(struct lxc_container *c, int timeout) +WRAP_API(bool, lxcapi_reboot) + +static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) { bool retv; pid_t pid; @@ -1386,18 +1499,20 @@ static bool lxcapi_shutdown(struct lxc_container *c, int timeout) if (!c) return false; - if (!c->is_running(c)) + if (!do_lxcapi_is_running(c)) return true; - pid = c->init_pid(c); + pid = do_lxcapi_init_pid(c); if (pid <= 0) return true; if (c->lxc_conf && c->lxc_conf->haltsignal) haltsignal = c->lxc_conf->haltsignal; kill(pid, haltsignal); - retv = c->wait(c, "STOPPED", timeout); + retv = do_lxcapi_wait(c, "STOPPED", timeout); return retv; } +WRAP_API_1(bool, lxcapi_shutdown, int) + static bool lxcapi_createl(struct lxc_container *c, const char *t, const char *bdevtype, struct bdev_specs *specs, int flags, ...) { @@ -1408,6 +1523,9 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t, if (!c) return false; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + /* * since we're going to wait for create to finish, I don't think we * need to get a copy of the arguments. @@ -1420,10 +1538,11 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t, goto out; } - bret = c->create(c, t, bdevtype, specs, flags, args); + bret = do_lxcapi_create(c, t, bdevtype, specs, flags, args); out: free(args); + current_config = old; return bret; } @@ -1441,7 +1560,7 @@ static void do_clear_unexp_config_line(struct lxc_conf *conf, const char *key) WARN("Error clearing configuration for %s", key); } -static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key) +static bool do_lxcapi_clear_config_item(struct lxc_container *c, const char *key) { int ret; @@ -1456,9 +1575,11 @@ static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key) return ret == 0; } +WRAP_API_1(bool, lxcapi_clear_config_item, const char *) + static inline bool enter_net_ns(struct lxc_container *c) { - pid_t pid = c->init_pid(c); + pid_t pid = do_lxcapi_init_pid(c); if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) && access("/proc/self/ns/user", F_OK) == 0) { if (!switch_to_ns(pid, "user")) @@ -1538,7 +1659,7 @@ static bool remove_from_array(char ***names, char *cname, int size) return false; } -static char** lxcapi_get_interfaces(struct lxc_container *c) +static char ** do_lxcapi_get_interfaces(struct lxc_container *c) { pid_t pid; int i, count = 0, pipefd[2]; @@ -1625,7 +1746,9 @@ static char** lxcapi_get_interfaces(struct lxc_container *c) return interfaces; } -static char** lxcapi_get_ips(struct lxc_container *c, const char* interface, const char* family, int scope) +WRAP_API(char **, lxcapi_get_interfaces) + +static char** do_lxcapi_get_ips(struct lxc_container *c, const char* interface, const char* family, int scope) { pid_t pid; int i, count = 0, pipefd[2]; @@ -1742,7 +1865,9 @@ static char** lxcapi_get_ips(struct lxc_container *c, const char* interface, con return addresses; } -static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) +WRAP_API_3(char **, lxcapi_get_ips, const char *, const char *, int) + +static int do_lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) { int ret; @@ -1755,7 +1880,9 @@ static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char return ret; } -static char* lxcapi_get_running_config_item(struct lxc_container *c, const char *key) +WRAP_API_3(int, lxcapi_get_config_item, const char *, char *, int) + +static char* do_lxcapi_get_running_config_item(struct lxc_container *c, const char *key) { char *ret; @@ -1763,12 +1890,14 @@ static char* lxcapi_get_running_config_item(struct lxc_container *c, const char return NULL; if (container_mem_lock(c)) return NULL; - ret = lxc_cmd_get_config_item(c->name, key, c->get_config_path(c)); + ret = lxc_cmd_get_config_item(c->name, key, do_lxcapi_get_config_path(c)); container_mem_unlock(c); return ret; } -static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen) +WRAP_API_1(char *, lxcapi_get_running_config_item, const char *) + +static int do_lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen) { if (!key) return lxc_listconfigs(retv, inlen); @@ -1788,7 +1917,9 @@ static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, return ret; } -static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file) +WRAP_API_3(int, lxcapi_get_keys, const char *, char *, int) + +static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) { FILE *fout; bool ret = false, need_disklock = false; @@ -1801,7 +1932,7 @@ static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file) // If we haven't yet loaded a config, load the stock config if (!c->lxc_conf) { - if (!c->load_config(c, lxc_global_config_value("lxc.default_config"))) { + if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) { ERROR("Error loading default configuration file %s while saving %s", lxc_global_config_value("lxc.default_config"), c->name); return false; } @@ -1841,6 +1972,8 @@ out: return ret; } +WRAP_API_1(bool, lxcapi_save_config, const char *) + static bool mod_rdep(struct lxc_container *c, bool inc) { char path[MAXPATHLEN]; @@ -2029,7 +2162,7 @@ static bool container_destroy(struct lxc_container *c) bool bret = false; int ret; - if (!c || !lxcapi_is_defined(c)) + if (!c || !do_lxcapi_is_defined(c)) return false; if (container_disk_lock(c)) @@ -2054,7 +2187,7 @@ static bool container_destroy(struct lxc_container *c) mod_all_rdeps(c, false); - const char *p1 = lxcapi_get_config_path(c); + const char *p1 = do_lxcapi_get_config_path(c); char *path = alloca(strlen(p1) + strlen(c->name) + 2); sprintf(path, "%s/%s", p1, c->name); if (am_unpriv()) @@ -2072,7 +2205,7 @@ out: return bret; } -static bool lxcapi_destroy(struct lxc_container *c) +static bool do_lxcapi_destroy(struct lxc_container *c) { if (!c || !lxcapi_is_defined(c)) return false; @@ -2089,9 +2222,9 @@ static bool lxcapi_destroy(struct lxc_container *c) return container_destroy(c); } -static bool lxcapi_snapshot_destroy_all(struct lxc_container *c); +WRAP_API(bool, lxcapi_destroy) -static bool lxcapi_destroy_with_snapshots(struct lxc_container *c) +static bool do_lxcapi_destroy_with_snapshots(struct lxc_container *c) { if (!c || !lxcapi_is_defined(c)) return false; @@ -2102,6 +2235,8 @@ static bool lxcapi_destroy_with_snapshots(struct lxc_container *c) return lxcapi_destroy(c); } +WRAP_API(bool, lxcapi_destroy_with_snapshots) + static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v) { struct lxc_config_t *config; @@ -2118,7 +2253,7 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con return do_append_unexp_config_line(c->lxc_conf, key, v); } -static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v) +static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v) { bool b = false; @@ -2134,6 +2269,8 @@ static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, con return b; } +WRAP_API_2(bool, lxcapi_set_config_item, const char *, const char *) + static char *lxcapi_config_file_name(struct lxc_container *c) { if (!c || !c->configfile) @@ -2181,7 +2318,7 @@ static bool set_config_filename(struct lxc_container *c) return true; } -static bool lxcapi_set_config_path(struct lxc_container *c, const char *path) +static bool do_lxcapi_set_config_path(struct lxc_container *c, const char *path) { char *p; bool b = false; @@ -2219,8 +2356,9 @@ err: return b; } +WRAP_API_1(bool, lxcapi_set_config_path, const char *) -static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) +static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) { int ret; @@ -2239,7 +2377,9 @@ static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, return ret == 0; } -static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) +WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *) + +static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) { int ret; @@ -2258,6 +2398,8 @@ static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, c return ret; } +WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int) + const char *lxc_get_global_config_item(const char *key) { return lxc_global_config_value(key); @@ -2374,7 +2516,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) ERROR("Error saving new hooks in clone"); return -1; } - c->save_config(c, NULL); + do_lxcapi_save_config(c, NULL); return 0; } @@ -2646,7 +2788,7 @@ static int create_file_dirname(char *path, struct lxc_conf *conf) return ret; } -static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname, +static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char *newname, const char *lxcpath, int flags, const char *bdevtype, const char *bdevdata, uint64_t newsize, char **hookargs) @@ -2659,7 +2801,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n FILE *fout; pid_t pid; - if (!c || !c->is_defined(c)) + if (!c || !do_lxcapi_is_defined(c)) return NULL; if (container_mem_lock(c)) @@ -2674,7 +2816,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n if (!newname) newname = c->name; if (!lxcpath) - lxcpath = c->get_config_path(c); + lxcpath = do_lxcapi_get_config_path(c); ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname); if (ret < 0 || ret >= MAXPATHLEN) { SYSERROR("clone: failed making config pathname"); @@ -2803,7 +2945,20 @@ out: return NULL; } -static bool lxcapi_rename(struct lxc_container *c, const char *newname) +static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname, + const char *lxcpath, int flags, + const char *bdevtype, const char *bdevdata, uint64_t newsize, + char **hookargs) +{ + struct lxc_container * ret; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs); + current_config = old; + return ret; +} + +static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) { struct bdev *bdev; struct lxc_container *newc; @@ -2838,15 +2993,24 @@ static bool lxcapi_rename(struct lxc_container *c, const char *newname) return true; } +WRAP_API_1(bool, lxcapi_rename, const char *) + static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process) { + struct lxc_conf *old = current_config; + int ret; + if (!c) return -1; - return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process); + current_config = c->lxc_conf; + + ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process); + current_config = old; + return ret; } -static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) +static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) { lxc_attach_command_t command; pid_t pid; @@ -2865,6 +3029,16 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t return lxc_wait_for_pid_status(pid); } +static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) +{ + int ret; + struct lxc_conf *old = current_config; + current_config = c ? c->lxc_conf : NULL; + ret = do_lxcapi_attach_run_wait(c, options, program, argv); + current_config = old; + return ret; +} + static int get_next_index(const char *lxcpath, char *cname) { char *fname; @@ -2908,7 +3082,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath) return true; } -static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile) +static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) { int i, flags, ret; struct lxc_container *c2; @@ -2950,7 +3124,7 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile) ERROR("and keep the original container pristine."); flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; } - c2 = c->clone(c, newname, snappath, flags, NULL, NULL, 0, NULL); + c2 = do_lxcapi_clone(c, newname, snappath, flags, NULL, NULL, 0, NULL); if (!c2) { ERROR("clone of %s:%s failed", c->config_path, c->name); return -1; @@ -2998,6 +3172,8 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile) return i; } +WRAP_API_1(int, lxcapi_snapshot, const char *) + static void lxcsnap_free(struct lxc_snapshot *s) { free(s->name); @@ -3052,7 +3228,7 @@ static char *get_timestamp(char* snappath, char *name) return s; } -static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps) +static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps) { char snappath[MAXPATHLEN], path2[MAXPATHLEN]; int count = 0, ret; @@ -3128,7 +3304,9 @@ out_free: return -1; } -static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname) +WRAP_API_1(int, lxcapi_snapshot_list, struct lxc_snapshot **) + +static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname) { char clonelxcpath[MAXPATHLEN]; int flags = 0; @@ -3189,6 +3367,8 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam return b; } +WRAP_API_2(bool, lxcapi_snapshot_restore, const char *, const char *) + static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath) { struct lxc_container *snap = NULL; @@ -3200,7 +3380,7 @@ static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath) goto err; } - if (!lxcapi_destroy(snap)) { + if (!do_lxcapi_destroy(snap)) { ERROR("Could not destroy snapshot %s", snapname); goto err; } @@ -3244,7 +3424,7 @@ static bool remove_all_snapshots(const char *path) return bret; } -static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname) +static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname) { char clonelxcpath[MAXPATHLEN]; @@ -3257,7 +3437,9 @@ static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapnam return do_snapshot_destroy(snapname, clonelxcpath); } -static bool lxcapi_snapshot_destroy_all(struct lxc_container *c) +WRAP_API_1(bool, lxcapi_snapshot_destroy, const char *) + +static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c) { char clonelxcpath[MAXPATHLEN]; @@ -3270,11 +3452,15 @@ static bool lxcapi_snapshot_destroy_all(struct lxc_container *c) return remove_all_snapshots(clonelxcpath); } -static bool lxcapi_may_control(struct lxc_container *c) +WRAP_API(bool, lxcapi_snapshot_destroy_all) + +static bool do_lxcapi_may_control(struct lxc_container *c) { return lxc_try_cmd(c->name, c->config_path) == 0; } +WRAP_API(bool, lxcapi_may_control) + static bool do_add_remove_node(pid_t init_pid, const char *path, bool add, struct stat *st) { @@ -3338,7 +3524,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path const char *p; /* make sure container is running */ - if (!c->is_running(c)) { + if (!do_lxcapi_is_running(c)) { ERROR("container is not running"); return false; } @@ -3362,17 +3548,17 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path if (ret < 0 || ret >= MAX_BUFFER) return false; - if (!do_add_remove_node(c->init_pid(c), p, add, &st)) + if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st)) return false; /* add or remove device to/from cgroup access list */ if (add) { - if (!c->set_cgroup_item(c, "devices.allow", value)) { + if (!do_lxcapi_set_cgroup_item(c, "devices.allow", value)) { ERROR("set_cgroup_item failed while adding the device node"); return false; } } else { - if (!c->set_cgroup_item(c, "devices.deny", value)) { + if (!do_lxcapi_set_cgroup_item(c, "devices.deny", value)) { ERROR("set_cgroup_item failed while removing the device node"); return false; } @@ -3381,7 +3567,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path return true; } -static bool lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) +static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) { if (am_unpriv()) { ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); @@ -3390,7 +3576,9 @@ static bool lxcapi_add_device_node(struct lxc_container *c, const char *src_path return add_remove_device_node(c, src_path, dest_path, true); } -static bool lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) +WRAP_API_2(bool, lxcapi_add_device_node, const char *, const char *) + +static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path) { if (am_unpriv()) { ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); @@ -3399,7 +3587,9 @@ static bool lxcapi_remove_device_node(struct lxc_container *c, const char *src_p return add_remove_device_node(c, src_path, dest_path, false); } -static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname, +WRAP_API_2(bool, lxcapi_remove_device_node, const char *, const char *) + +static bool do_lxcapi_attach_interface(struct lxc_container *c, const char *ifname, const char *dst_ifname) { int ret = 0; @@ -3422,7 +3612,7 @@ static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname, goto err; } - ret = lxc_netdev_move_by_name(ifname, c->init_pid(c), dst_ifname); + ret = lxc_netdev_move_by_name(ifname, do_lxcapi_init_pid(c), dst_ifname); if (ret) goto err; @@ -3432,7 +3622,9 @@ err: return false; } -static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname, +WRAP_API_2(bool, lxcapi_attach_interface, const char *, const char *) + +static bool do_lxcapi_detach_interface(struct lxc_container *c, const char *ifname, const char *dst_ifname) { pid_t pid, pid_outside; @@ -3487,6 +3679,8 @@ static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname, return true; } +WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *) + struct criu_opts { /* The type of criu invocation, one of "dump" or "restore" */ char *action; @@ -3510,11 +3704,15 @@ struct criu_opts { static void exec_criu(struct criu_opts *opts) { - char **argv, log[PATH_MAX], buf[257]; + char **argv, log[PATH_MAX]; int static_args = 14, argc = 0, i, ret; int netnr = 0; struct lxc_list *it; + struct mntent mntent; + char buf[4096]; + FILE *mnts = NULL; + /* The command line always looks like: * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \ * --manage-cgroups action-script foo.sh -D $(directory) \ @@ -3545,6 +3743,11 @@ static void exec_criu(struct criu_opts *opts) return; } + // We need to tell criu where cgmanager's socket is bind mounted from + // if it exists since it's external. + if (cgroup_driver() == CGMANAGER) + static_args+=2; + argv = malloc(static_args * sizeof(*argv)); if (!argv) return; @@ -3584,9 +3787,35 @@ static void exec_criu(struct criu_opts *opts) if (opts->verbose) DECLARE_ARG("-vvvvvv"); + /* + * Note: this macro is not intended to be called unless argc is equal + * to the length of the array; there is nothing that keeps track of the + * length of the array besides the location in the code that this is + * called. (Yes this is bad, and we should fix it.) + */ +#define RESIZE_ARGS(additional) \ + do { \ + void *m; \ + if (additional < 0) { \ + ERROR("resizing by negative amount"); \ + goto err; \ + } else if (additional == 0) \ + continue; \ + \ + m = realloc(argv, (argc + additional + 1) * sizeof(*argv)); \ + if (!m) \ + goto err; \ + argv = m; \ + } while (0) + if (strcmp(opts->action, "dump") == 0) { char pid[32]; + if (cgroup_driver() == CGMANAGER) { + DECLARE_ARG("--ext-mount-map"); + DECLARE_ARG("/sys/fs/cgroup/cgmanager:cgmanager"); + } + if (sprintf(pid, "%d", lxcapi_init_pid(opts->c)) < 0) goto err; @@ -3595,6 +3824,12 @@ static void exec_criu(struct criu_opts *opts) if (!opts->stop) DECLARE_ARG("--leave-running"); } else if (strcmp(opts->action, "restore") == 0) { + + if (cgroup_driver() == CGMANAGER) { + DECLARE_ARG("--ext-mount-map"); + DECLARE_ARG("cgmanager:/sys/fs/cgroup/cgmanager"); + } + DECLARE_ARG("--root"); DECLARE_ARG(opts->c->lxc_conf->rootfs.mount); DECLARE_ARG("--restore-detached"); @@ -3604,9 +3839,10 @@ static void exec_criu(struct criu_opts *opts) DECLARE_ARG("--cgroup-root"); DECLARE_ARG(opts->cgroup_path); + RESIZE_ARGS(lxc_list_len(&opts->c->lxc_conf->network) * 2); + lxc_list_for_each(it, &opts->c->lxc_conf->network) { char eth[128], *veth; - void *m; struct lxc_netdev *n = it->elem; if (n->name) { @@ -3622,18 +3858,42 @@ static void exec_criu(struct criu_opts *opts) if (ret < 0 || ret >= sizeof(buf)) goto err; - /* final NULL and --veth-pair eth0=vethASDF */ - m = realloc(argv, (argc + 1 + 2) * sizeof(*argv)); - if (!m) - goto err; - argv = m; - DECLARE_ARG("--veth-pair"); DECLARE_ARG(buf); - argv[argc] = NULL; + } + } + + // CRIU wants to know about any external bind mounts the + // container has. + mnts = write_mount_file(&opts->c->lxc_conf->mount_list); + if (!mnts) + goto err; + + RESIZE_ARGS(lxc_list_len(&opts->c->lxc_conf->mount_list) * 2); + + while (getmntent_r(mnts, &mntent, buf, sizeof(buf))) { + char arg[2048], *key, *val; + int ret; + if (strcmp(opts->action, "dump") == 0) { + key = mntent.mnt_fsname; + val = mntent.mnt_dir; + } else { + key = mntent.mnt_dir; + val = mntent.mnt_fsname; + } + + ret = snprintf(arg, sizeof(arg), "%s:%s", key, val); + if (ret < 0 || ret >= sizeof(arg)) { + goto err; } + + DECLARE_ARG("--ext-mount-map"); + DECLARE_ARG(arg); } + fclose(mnts); + + argv[argc] = NULL; netnr = 0; lxc_list_for_each(it, &opts->c->lxc_conf->network) { @@ -3669,8 +3929,11 @@ static void exec_criu(struct criu_opts *opts) } #undef DECLARE_ARG +#undef RESIZE_ARGS execv(argv[0], argv); err: + if (mnts) + fclose(mnts); for (i = 0; argv[i]; i++) free(argv[i]); free(argv); @@ -3778,7 +4041,7 @@ out: return true; } -static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose) +static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose) { pid_t pid; int status; @@ -3811,7 +4074,7 @@ static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool sto } else { pid_t w = waitpid(pid, &status, 0); if (w == -1) { - perror("waitpid"); + SYSERROR("waitpid"); return false; } @@ -3823,6 +4086,8 @@ static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool sto } } +WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool) + static bool restore_net_info(struct lxc_container *c) { struct lxc_list *it; @@ -3850,28 +4115,21 @@ out_unlock: return !has_error; } -static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbose) +// do_restore never returns, the calling process is used as the +// monitor process. do_restore calls exit() if it fails. +static void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose) { pid_t pid; - struct lxc_rootfs *rootfs; char pidfile[L_tmpnam]; struct lxc_handler *handler; - bool has_error = true; - - if (!criu_ok(c)) - return false; - - if (geteuid()) { - ERROR("Must be root to restore\n"); - return false; - } + int status; if (!tmpnam(pidfile)) - return false; + goto out; handler = lxc_init(c->name, c->lxc_conf, c->config_path); if (!handler) - return false; + goto out; if (!cgroup_init(handler)) { ERROR("failed initing cgroups"); @@ -3888,15 +4146,21 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos goto out_fini_handler; } + resolve_clone_flags(handler); + pid = fork(); if (pid < 0) goto out_fini_handler; if (pid == 0) { struct criu_opts os; + struct lxc_rootfs *rootfs; + + close(pipe); + pipe = -1; if (unshare(CLONE_NEWNS)) - exit(1); + goto out_fini_handler; /* CRIU needs the lxc root bind mounted so that it is the root of some * mount. */ @@ -3904,15 +4168,14 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos if (rootfs_is_blockdev(c->lxc_conf)) { if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0) - exit(1); - } - else { + goto out_fini_handler; + } else { if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST) - exit(1); + goto out_fini_handler; if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) { rmdir(rootfs->mount); - exit(1); + goto out_fini_handler; } } @@ -3927,27 +4190,34 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos exec_criu(&os); umount(rootfs->mount); rmdir(rootfs->mount); - exit(1); + goto out_fini_handler; } else { - int status; + int ret; + char title[2048]; pid_t w = waitpid(pid, &status, 0); - if (w == -1) { - perror("waitpid"); + SYSERROR("waitpid"); + goto out_fini_handler; + } + + ret = write(pipe, &status, sizeof(status)); + close(pipe); + pipe = -1; + + if (sizeof(status) != ret) { + SYSERROR("failed to write all of status"); goto out_fini_handler; } if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { goto out_fini_handler; - } - else { + } else { int ret; FILE *f = fopen(pidfile, "r"); if (!f) { - perror("reading pidfile"); - ERROR("couldn't read restore's init pidfile %s\n", pidfile); + SYSERROR("couldn't read restore's init pidfile %s\n", pidfile); goto out_fini_handler; } @@ -3966,19 +4236,92 @@ static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbos goto out_fini_handler; } - if (lxc_poll(c->name, handler)) { + /* + * See comment in lxcapi_start; we don't care if these + * fail because it's just a beauty thing. We just + * assign the return here to silence potential. + */ + ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name); + ret = setproctitle(title); + + ret = lxc_poll(c->name, handler); + if (ret) lxc_abort(c->name, handler); - goto out_fini_handler; - } + lxc_fini(c->name, handler); + exit(ret); } - has_error = false; - out_fini_handler: lxc_fini(c->name, handler); - return !has_error; + +out: + if (pipe >= 0) { + status = 1; + if (write(pipe, &status, sizeof(status)) != sizeof(status)) { + SYSERROR("writing status failed"); + } + close(pipe); + } + + exit(1); } +static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool verbose) +{ + pid_t pid; + int status, nread; + int pipefd[2]; + + if (!criu_ok(c)) + return false; + + if (geteuid()) { + ERROR("Must be root to restore\n"); + return false; + } + + if (pipe(pipefd)) { + ERROR("failed to create pipe"); + return false; + } + + pid = fork(); + if (pid < 0) { + close(pipefd[0]); + close(pipefd[1]); + return false; + } + + if (pid == 0) { + close(pipefd[0]); + // this never returns + do_restore(c, pipefd[1], directory, verbose); + } + + close(pipefd[1]); + + nread = read(pipefd[0], &status, sizeof(status)); + close(pipefd[0]); + if (sizeof(status) != nread) { + ERROR("reading status from pipe failed"); + goto err_wait; + } + + // If the criu process was killed or exited nonzero, wait() for the + // handler, since the restore process died. Otherwise, we don't need to + // wait, since the child becomes the monitor process. + if (!WIFEXITED(status) || WEXITSTATUS(status)) + goto err_wait; + return true; + +err_wait: + if (wait_for_pid(pid)) + ERROR("restore process died"); + return false; +} + +WRAP_API_2(bool, lxcapi_restore, char *, bool) + static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...) { va_list ap; @@ -3988,18 +4331,24 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t if (!c) return -1; + struct lxc_conf *old = current_config; + current_config = c->lxc_conf; + va_start(ap, arg); argv = lxc_va_arg_list_to_argv_const(ap, 1); va_end(ap); if (!argv) { ERROR("Memory allocation error."); - return -1; + ret = -1; + goto out; } argv[0] = arg; - ret = lxcapi_attach_run_wait(c, options, program, (const char * const *)argv); + ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv); free((void*)argv); +out: + current_config = old; return ret; } @@ -4116,12 +4465,6 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->checkpoint = lxcapi_checkpoint; c->restore = lxcapi_restore; - /* we'll allow the caller to update these later */ - if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) { - fprintf(stderr, "failed to open log\n"); - goto err; - } - return c; err: @@ -4195,7 +4538,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta goto free_bad; continue; } - if (!lxcapi_is_defined(c)) { + if (!do_lxcapi_is_defined(c)) { INFO("Container %s:%s has a config but is not defined", lxcpath, direntp->d_name); if (names) diff --git a/src/lxc/start.c b/src/lxc/start.c index 70e4693..d615375 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -840,6 +840,35 @@ static int recv_ttys_from_child(struct lxc_handler *handler) return 0; } +void resolve_clone_flags(struct lxc_handler *handler) +{ + handler->clone_flags = CLONE_NEWPID | CLONE_NEWNS; + + if (!lxc_list_empty(&handler->conf->id_map)) { + INFO("Cloning a new user namespace"); + handler->clone_flags |= CLONE_NEWUSER; + } + + if (handler->conf->inherit_ns_fd[LXC_NS_NET] == -1) { + if (!lxc_requests_empty_network(handler)) + handler->clone_flags |= CLONE_NEWNET; + } else { + INFO("Inheriting a net namespace"); + } + + if (handler->conf->inherit_ns_fd[LXC_NS_IPC] == -1) { + handler->clone_flags |= CLONE_NEWIPC; + } else { + INFO("Inheriting an IPC namespace"); + } + + if (handler->conf->inherit_ns_fd[LXC_NS_UTS] == -1) { + handler->clone_flags |= CLONE_NEWUTS; + } else { + INFO("Inheriting a UTS namespace"); + } +} + static int lxc_spawn(struct lxc_handler *handler) { int failed_before_rename = 0; @@ -858,21 +887,14 @@ static int lxc_spawn(struct lxc_handler *handler) if (lxc_sync_init(handler)) return -1; - handler->clone_flags = CLONE_NEWPID|CLONE_NEWNS; - if (!lxc_list_empty(&handler->conf->id_map)) { - INFO("Cloning a new user namespace"); - handler->clone_flags |= CLONE_NEWUSER; - } - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handler->ttysock) < 0) { lxc_sync_fini(handler); return -1; } - if (handler->conf->inherit_ns_fd[LXC_NS_NET] == -1) { - if (!lxc_requests_empty_network(handler)) - handler->clone_flags |= CLONE_NEWNET; + resolve_clone_flags(handler); + if (handler->clone_flags & CLONE_NEWNET) { if (!lxc_list_empty(&handler->conf->network)) { /* Find gateway addresses from the link device, which is @@ -899,23 +921,8 @@ static int lxc_spawn(struct lxc_handler *handler) ERROR("failed to save physical nic info"); goto out_abort; } - } else { - INFO("Inheriting a net namespace"); } - if (handler->conf->inherit_ns_fd[LXC_NS_IPC] == -1) { - handler->clone_flags |= CLONE_NEWIPC; - } else { - INFO("Inheriting an IPC namespace"); - } - - if (handler->conf->inherit_ns_fd[LXC_NS_UTS] == -1) { - handler->clone_flags |= CLONE_NEWUTS; - } else { - INFO("Inheriting a UTS namespace"); - } - - if (!cgroup_init(handler)) { ERROR("failed initializing cgroup support"); goto out_delete_net; diff --git a/src/lxc/start.h b/src/lxc/start.h index 2c6fc0d..aab063a 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -87,5 +87,6 @@ extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall, int fd_to_i int __lxc_start(const char *, struct lxc_conf *, struct lxc_operations *, void *, const char *); +extern void resolve_clone_flags(struct lxc_handler *handler); #endif diff --git a/src/lxc/utils.c b/src/lxc/utils.c index e66a01f..1df6e8f 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -68,8 +69,8 @@ lxc_log_define(lxc_utils, lxc); -static int _recursive_rmdir_onedev(char *dirname, dev_t pdev, - const char *exclude, int level) +static int _recursive_rmdir(char *dirname, dev_t pdev, + const char *exclude, int level, bool onedev) { struct dirent dirent, *direntp; DIR *dir; @@ -106,7 +107,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev, if (ret < 0) { switch(errno) { case ENOTEMPTY: - INFO("Not deleting snapshots"); + INFO("Not deleting snapshot %s", pathname); hadexclude = true; break; case ENOTDIR: @@ -129,14 +130,14 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev, failed=1; continue; } - if (mystat.st_dev != pdev) + if (onedev && mystat.st_dev != pdev) continue; if (S_ISDIR(mystat.st_mode)) { - if (_recursive_rmdir_onedev(pathname, pdev, exclude, level+1) < 0) + if (_recursive_rmdir(pathname, pdev, exclude, level+1, onedev) < 0) failed=1; } else { if (unlink(pathname) < 0) { - ERROR("%s: failed to delete %s", __func__, pathname); + SYSERROR("%s: failed to delete %s", __func__, pathname); failed=1; } } @@ -158,17 +159,41 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev, return failed ? -1 : 0; } +/* we have two different magic values for overlayfs, yay */ +#define OVERLAYFS_SUPER_MAGIC 0x794c764f +#define OVERLAY_SUPER_MAGIC 0x794c7630 +/* + * In overlayfs, st_dev is unreliable. so on overlayfs we don't do + * the lxc_rmdir_onedev() + */ +static bool is_native_overlayfs(const char *path) +{ + struct statfs sb; + + if (statfs(path, &sb) < 0) + return false; + if (sb.f_type == OVERLAYFS_SUPER_MAGIC || + sb.f_type == OVERLAY_SUPER_MAGIC) + return true; + return false; +} + /* returns 0 on success, -1 if there were any failures */ extern int lxc_rmdir_onedev(char *path, const char *exclude) { struct stat mystat; + bool onedev = true; + + if (is_native_overlayfs(path)) { + onedev = false; + } if (lstat(path, &mystat) < 0) { ERROR("%s: failed to stat %s", __func__, path); return -1; } - return _recursive_rmdir_onedev(path, mystat.st_dev, exclude, 0); + return _recursive_rmdir(path, mystat.st_dev, exclude, 0, onedev); } static int mount_fs(const char *source, const char *target, const char *type) @@ -322,7 +347,7 @@ const char *lxc_global_config_value(const char *option_name) sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home); sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home); sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home); - user_cgroup_pattern = strdup("%n"); + user_cgroup_pattern = strdup("lxc/%n"); } else { user_config_path = strdup(LXC_GLOBAL_CONF); diff --git a/src/lxc/version.h b/src/lxc/version.h index ff6b926..40c3b5e 100644 --- a/src/lxc/version.h +++ b/src/lxc/version.h @@ -25,7 +25,7 @@ #define LXC_VERSION_MAJOR 1 #define LXC_VERSION_MINOR 1 -#define LXC_VERSION_MICRO 1 -#define LXC_VERSION "1.1.1" +#define LXC_VERSION_MICRO 2 +#define LXC_VERSION "1.1.2" #endif diff --git a/src/tests/aa.c b/src/tests/aa.c index b8689ac..1ab1997 100644 --- a/src/tests/aa.c +++ b/src/tests/aa.c @@ -47,9 +47,11 @@ static int test_attach_write_file(void* payload) if (f) { printf("yes\n"); fclose(f); + fflush(NULL); return 1; } printf("no\n"); + fflush(NULL); return 0; } diff --git a/src/tests/concurrent.c b/src/tests/concurrent.c index acabbed..f32411a 100644 --- a/src/tests/concurrent.c +++ b/src/tests/concurrent.c @@ -182,6 +182,10 @@ int main(int argc, char *argv[]) { (tok = strtok_r(mode_tok, ",", &saveptr)); i++, mode_tok = NULL) { modes = realloc(modes, sizeof(*modes) * (i+2)); + if (!modes) { + perror("realloc"); + exit(EXIT_FAILURE); + } modes[i] = tok; } modes[i] = NULL; diff --git a/templates/lxc-centos.in b/templates/lxc-centos.in index 1588042..265b7d0 100644 --- a/templates/lxc-centos.in +++ b/templates/lxc-centos.in @@ -350,7 +350,7 @@ EOF # prevent mingetty from calling vhangup(2) since it fails with userns. # Same issue as oracle template: prevent mingetty from calling vhangup(2) # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589. - sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/init/tty.conf + sed -i 's|mingetty|mingetty --nohangup|' $rootfs_path/etc/init/tty.conf if [ ${root_display_password} = "yes" ] then @@ -413,10 +413,10 @@ download_centos() # download a mini centos into a cache echo "Downloading centos minimal ..." - if [ $release -le 5 ];then - YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck" - else + if yum -h | grep -q 'releasever=RELEASEVER'; then YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck --releasever=$release" + else + YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck" fi PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"