Imported Upstream version 2.0.0 upstream/2.0.0
authorDariusz Michaluk <d.michaluk@samsung.com>
Fri, 15 Apr 2016 11:53:16 +0000 (13:53 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Fri, 15 Apr 2016 11:53:16 +0000 (13:53 +0200)
267 files changed:
Makefile.in
aclocal.m4
config/Makefile.in
config/apparmor/Makefile.am
config/apparmor/Makefile.in
config/apparmor/abstractions/container-base
config/apparmor/abstractions/container-base.in
config/apparmor/lxc-generate-aa-rules.py
config/apparmor/profiles/lxc-default-cgns [new file with mode: 0644]
config/apparmor/profiles/lxc-default-with-nesting
config/bash/Makefile.in
config/bash/lxc
config/bash/lxc.in
config/compile
config/config.guess
config/config.sub
config/depcomp
config/etc/Makefile.in
config/init/Makefile.in
config/init/common/Makefile.am
config/init/common/Makefile.in
config/init/common/lxc-devsetup [moved from config/init/systemd/lxc-devsetup with 100% similarity]
config/init/common/lxc-net.in
config/init/systemd/Makefile.am
config/init/systemd/Makefile.in
config/init/systemd/lxc@.service.in [new file with mode: 0644]
config/init/sysvinit/Makefile.in
config/init/sysvinit/lxc-containers.in
config/init/upstart/Makefile.am
config/init/upstart/Makefile.in
config/init/upstart/lxc.conf
config/init/upstart/lxc.conf.in [new file with mode: 0644]
config/install-sh
config/missing
config/selinux/Makefile.in
config/sysconfig/Makefile.in
config/templates/Makefile.am
config/templates/Makefile.in
config/templates/alpine.common.conf.in [new file with mode: 0644]
config/templates/alpine.userns.conf.in [new file with mode: 0644]
config/templates/common.conf.d/Makefile.in
config/templates/common.conf.in
config/templates/debian.common.conf.in
config/templates/slackware.common.conf.in [new file with mode: 0644]
config/templates/slackware.userns.conf.in [new file with mode: 0644]
config/templates/sparclinux.common.conf.in [new file with mode: 0644]
config/templates/sparclinux.userns.conf.in [new file with mode: 0644]
config/templates/ubuntu.common.conf.in
config/yum/Makefile.in
configure
configure.ac
doc/Makefile.am
doc/Makefile.in
doc/api/Makefile.in
doc/examples/Makefile.in
doc/ja/Makefile.am
doc/ja/Makefile.in
doc/ja/legacy/lxc-ls.sgml.in [deleted file]
doc/ja/lxc-attach.sgml.in
doc/ja/lxc-checkpoint.sgml.in
doc/ja/lxc-clone.sgml.in
doc/ja/lxc-console.sgml.in
doc/ja/lxc-copy.sgml.in [new file with mode: 0644]
doc/ja/lxc-create.sgml.in
doc/ja/lxc-destroy.sgml.in
doc/ja/lxc-device.sgml.in
doc/ja/lxc-info.sgml.in
doc/ja/lxc-ls.sgml.in
doc/ja/lxc-snapshot.sgml.in
doc/ja/lxc-start-ephemeral.sgml.in
doc/ja/lxc-stop.sgml.in
doc/ja/lxc-top.sgml.in
doc/ja/lxc-unshare.sgml.in
doc/ja/lxc-usernet.sgml.in
doc/ja/lxc-wait.sgml.in
doc/ja/lxc.container.conf.sgml.in
doc/ja/lxc.sgml.in
doc/ja/see_also.sgml.in
doc/ko/FAQ.txt [new file with mode: 0644]
doc/ko/Makefile.am [new file with mode: 0644]
doc/ko/Makefile.in [new file with mode: 0644]
doc/ko/common_options.sgml.in [new file with mode: 0644]
doc/ko/lxc-attach.sgml.in [new file with mode: 0644]
doc/ko/lxc-autostart.sgml.in [new file with mode: 0644]
doc/ko/lxc-cgroup.sgml.in [new file with mode: 0644]
doc/ko/lxc-checkconfig.sgml.in [new file with mode: 0644]
doc/ko/lxc-checkpoint.sgml.in [new file with mode: 0644]
doc/ko/lxc-clone.sgml.in [new file with mode: 0644]
doc/ko/lxc-config.sgml.in [new file with mode: 0644]
doc/ko/lxc-console.sgml.in [new file with mode: 0644]
doc/ko/lxc-copy.sgml.in [new file with mode: 0644]
doc/ko/lxc-create.sgml.in [new file with mode: 0644]
doc/ko/lxc-destroy.sgml.in [new file with mode: 0644]
doc/ko/lxc-device.sgml.in [new file with mode: 0644]
doc/ko/lxc-execute.sgml.in [new file with mode: 0644]
doc/ko/lxc-freeze.sgml.in [new file with mode: 0644]
doc/ko/lxc-info.sgml.in [new file with mode: 0644]
doc/ko/lxc-ls.sgml.in [new file with mode: 0644]
doc/ko/lxc-monitor.sgml.in [new file with mode: 0644]
doc/ko/lxc-snapshot.sgml.in [new file with mode: 0644]
doc/ko/lxc-start-ephemeral.sgml.in [new file with mode: 0644]
doc/ko/lxc-start.sgml.in [new file with mode: 0644]
doc/ko/lxc-stop.sgml.in [new file with mode: 0644]
doc/ko/lxc-top.sgml.in [new file with mode: 0644]
doc/ko/lxc-unfreeze.sgml.in [moved from doc/legacy/lxc-ls.sgml.in with 52% similarity]
doc/ko/lxc-unshare.sgml.in [new file with mode: 0644]
doc/ko/lxc-user-nic.sgml.in [new file with mode: 0644]
doc/ko/lxc-usernet.sgml.in [new file with mode: 0644]
doc/ko/lxc-usernsexec.sgml.in [new file with mode: 0644]
doc/ko/lxc-wait.sgml.in [new file with mode: 0644]
doc/ko/lxc.conf.sgml.in [new file with mode: 0644]
doc/ko/lxc.container.conf.sgml.in [new file with mode: 0644]
doc/ko/lxc.sgml.in [new file with mode: 0644]
doc/ko/lxc.system.conf.sgml.in [new file with mode: 0644]
doc/ko/see_also.sgml.in [new file with mode: 0644]
doc/lxc-attach.sgml.in
doc/lxc-checkpoint.sgml.in
doc/lxc-clone.sgml.in
doc/lxc-console.sgml.in
doc/lxc-copy.sgml.in [new file with mode: 0644]
doc/lxc-create.sgml.in
doc/lxc-destroy.sgml.in
doc/lxc-device.sgml.in
doc/lxc-info.sgml.in
doc/lxc-ls.sgml.in
doc/lxc-snapshot.sgml.in
doc/lxc-start-ephemeral.sgml.in
doc/lxc-stop.sgml.in
doc/lxc-top.sgml.in
doc/lxc-unshare.sgml.in
doc/lxc-usernet.sgml.in
doc/lxc-wait.sgml.in
doc/lxc.container.conf.sgml.in
doc/lxc.sgml.in
doc/rootfs/Makefile.in
doc/see_also.sgml.in
hooks/Makefile.am
hooks/Makefile.in
hooks/ubuntu-cloud-prep
hooks/unmount-namespace.c [new file with mode: 0644]
lxc.spec
lxc.spec.in
src/Makefile.in
src/config.h.in
src/include/getsubopt.c [new file with mode: 0644]
src/include/getsubopt.h [new file with mode: 0644]
src/include/ifaddrs.c
src/include/lxcmntent.h
src/lua-lxc/Makefile.in
src/lua-lxc/core.c
src/lua-lxc/lxc.lua
src/lxc/Makefile.am
src/lxc/Makefile.in
src/lxc/arguments.h
src/lxc/attach.c
src/lxc/bdev.c [deleted file]
src/lxc/bdev/bdev.c [new file with mode: 0644]
src/lxc/bdev/bdev.h [moved from src/lxc/bdev.h with 87% similarity]
src/lxc/bdev/lxcaufs.c [new file with mode: 0644]
src/lxc/bdev/lxcaufs.h [new file with mode: 0644]
src/lxc/bdev/lxcbtrfs.c [new file with mode: 0644]
src/lxc/bdev/lxcbtrfs.h [moved from src/lxc/lxc-btrfs.h with 63% similarity]
src/lxc/bdev/lxcdir.c [new file with mode: 0644]
src/lxc/bdev/lxcdir.h [new file with mode: 0644]
src/lxc/bdev/lxcloop.c [new file with mode: 0644]
src/lxc/bdev/lxcloop.h [new file with mode: 0644]
src/lxc/bdev/lxclvm.c [new file with mode: 0644]
src/lxc/bdev/lxclvm.h [new file with mode: 0644]
src/lxc/bdev/lxcnbd.c [new file with mode: 0644]
src/lxc/bdev/lxcnbd.h [new file with mode: 0644]
src/lxc/bdev/lxcoverlay.c [new file with mode: 0644]
src/lxc/bdev/lxcoverlay.h [new file with mode: 0644]
src/lxc/bdev/lxcrbd.c [new file with mode: 0644]
src/lxc/bdev/lxcrbd.h [new file with mode: 0644]
src/lxc/bdev/lxcrsync.c [new file with mode: 0644]
src/lxc/bdev/lxcrsync.h [new file with mode: 0644]
src/lxc/bdev/lxczfs.c [new file with mode: 0644]
src/lxc/bdev/lxczfs.h [new file with mode: 0644]
src/lxc/cgfs.c
src/lxc/cgfsng.c [new file with mode: 0644]
src/lxc/cgmanager.c
src/lxc/cgroup.c
src/lxc/cgroup.h
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c
src/lxc/console.c
src/lxc/console.h
src/lxc/criu.c
src/lxc/criu.h
src/lxc/initutils.c
src/lxc/initutils.h
src/lxc/legacy/lxc-ls.in [deleted file]
src/lxc/list.h
src/lxc/log.c
src/lxc/lsm/apparmor.c
src/lxc/lxc-checkconfig.in
src/lxc/lxc-ls [deleted file]
src/lxc/lxc-ls.in [deleted file]
src/lxc/lxc-start-ephemeral.in
src/lxc/lxc_attach.c
src/lxc/lxc_autostart.c
src/lxc/lxc_checkpoint.c
src/lxc/lxc_clone.c
src/lxc/lxc_copy.c [new file with mode: 0644]
src/lxc/lxc_create.c
src/lxc/lxc_destroy.c
src/lxc/lxc_execute.c
src/lxc/lxc_ls.c [new file with mode: 0644]
src/lxc/lxc_snapshot.c
src/lxc/lxc_top.c
src/lxc/lxc_user_nic.c
src/lxc/lxc_usernsexec.c
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h
src/lxc/namespace.h
src/lxc/network.c
src/lxc/network.h
src/lxc/nl.c
src/lxc/seccomp.c
src/lxc/start.c
src/lxc/sync.c
src/lxc/sync.h
src/lxc/utils.c
src/lxc/utils.h
src/lxc/version.h
src/lxc/version.h.in
src/python-lxc/Makefile.in
src/python-lxc/examples/api_test.py
src/python-lxc/examples/pyconsole-vte.py
src/python-lxc/examples/pyconsole.py
src/python-lxc/lxc.c
src/python-lxc/lxc/__init__.py
src/python-lxc/setup.py.in
src/tests/Makefile.am
src/tests/Makefile.in
src/tests/attach.c
src/tests/get_item.c
src/tests/lxc-test-apparmor-mount
src/tests/lxc-test-automount [new file with mode: 0644]
src/tests/lxc-test-cloneconfig
src/tests/lxc-test-lxc-attach [new file with mode: 0755]
src/tests/lxc-test-snapdeps [new file with mode: 0644]
src/tests/lxc-test-ubuntu
src/tests/lxc-test-unpriv
src/tests/lxc-test-usernic.in
templates/Makefile.am
templates/Makefile.in
templates/lxc-alpine.in
templates/lxc-altlinux.in
templates/lxc-archlinux.in
templates/lxc-busybox.in
templates/lxc-centos.in
templates/lxc-cirros.in
templates/lxc-debian.in
templates/lxc-download.in
templates/lxc-fedora.in
templates/lxc-gentoo.in
templates/lxc-openmandriva.in
templates/lxc-opensuse.in
templates/lxc-oracle.in
templates/lxc-plamo.in
templates/lxc-slackware.in [new file with mode: 0644]
templates/lxc-sparclinux.in [new file with mode: 0644]
templates/lxc-sshd.in
templates/lxc-ubuntu-cloud.in
templates/lxc-ubuntu.in

index 869a906..2de8b98 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # Makefile.am
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -83,27 +93,18 @@ host_triplet = @host@
 @ENABLE_LUA_TRUE@am__append_1 = --with lua
 @ENABLE_PYTHON_TRUE@am__append_2 = --with python
 subdir = .
-DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
-       $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(top_srcdir)/configure $(am__configure_deps) \
-       $(srcdir)/lxc.pc.in $(srcdir)/lxc.spec.in \
-       $(top_srcdir)/doc/legacy/lxc-ls.sgml.in \
-       $(top_srcdir)/doc/ja/legacy/lxc-ls.sgml.in \
-       $(top_srcdir)/src/lxc/legacy/lxc-ls.in COPYING \
-       $(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \
-       $(top_srcdir)/config/config.sub \
-       $(top_srcdir)/config/install-sh $(top_srcdir)/config/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+       $(am__configure_deps) $(am__DIST_COMMON)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
-CONFIG_CLEAN_FILES = lxc.pc lxc.spec doc/legacy/lxc-ls.sgml \
-       doc/ja/legacy/lxc-ls.sgml src/lxc/legacy/lxc-ls
+CONFIG_CLEAN_FILES = lxc.pc lxc.spec
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -189,6 +190,12 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc.pc.in \
+       $(srcdir)/lxc.spec.in $(top_srcdir)/config/compile \
+       $(top_srcdir)/config/config.guess \
+       $(top_srcdir)/config/config.sub \
+       $(top_srcdir)/config/install-sh $(top_srcdir)/config/missing \
+       AUTHORS COPYING ChangeLog INSTALL NEWS README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -282,6 +289,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -295,6 +303,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -386,6 +395,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -424,7 +434,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -447,12 +456,6 @@ lxc.pc: $(top_builddir)/config.status $(srcdir)/lxc.pc.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
 lxc.spec: $(top_builddir)/config.status $(srcdir)/lxc.spec.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
-doc/legacy/lxc-ls.sgml: $(top_builddir)/config.status $(top_srcdir)/doc/legacy/lxc-ls.sgml.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-doc/ja/legacy/lxc-ls.sgml: $(top_builddir)/config.status $(top_srcdir)/doc/ja/legacy/lxc-ls.sgml.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-src/lxc/legacy/lxc-ls: $(top_builddir)/config.status $(top_srcdir)/src/lxc/legacy/lxc-ls.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
 install-pcdataDATA: $(pcdata_DATA)
        @$(NORMAL_INSTALL)
        @list='$(pcdata_DATA)'; test -n "$(pcdatadir)" || list=; \
@@ -662,15 +665,15 @@ dist-xz: distdir
        $(am__post_remove_distdir)
 
 dist-tarZ: distdir
-       @echo WARNING: "Support for shar distribution archives is" \
-                      "deprecated." >&2
+       @echo WARNING: "Support for distribution archives compressed with" \
+                      "legacy program 'compress' is deprecated." >&2
        @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
        tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
        $(am__post_remove_distdir)
 
 dist-shar: distdir
-       @echo WARNING: "Support for distribution archives compressed with" \
-                      "legacy program 'compress' is deprecated." >&2
+       @echo WARNING: "Support for shar distribution archives is" \
+                      "deprecated." >&2
        @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
        shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
        $(am__post_remove_distdir)
@@ -706,17 +709,17 @@ distcheck: dist
        esac
        chmod -R a-w $(distdir)
        chmod u+w $(distdir)
-       mkdir $(distdir)/_build $(distdir)/_inst
+       mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
        chmod a-w $(distdir)
        test -d $(distdir)/_build || exit 0; \
        dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
          && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
          && am__cwd=`pwd` \
-         && $(am__cd) $(distdir)/_build \
-         && ../configure \
+         && $(am__cd) $(distdir)/_build/sub \
+         && ../../configure \
            $(AM_DISTCHECK_CONFIGURE_FLAGS) \
            $(DISTCHECK_CONFIGURE_FLAGS) \
-           --srcdir=.. --prefix="$$dc_install_base" \
+           --srcdir=../.. --prefix="$$dc_install_base" \
          && $(MAKE) $(AM_MAKEFLAGS) \
          && $(MAKE) $(AM_MAKEFLAGS) dvi \
          && $(MAKE) $(AM_MAKEFLAGS) check \
@@ -894,6 +897,8 @@ uninstall-am: uninstall-pcdataDATA
        mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
        tags-am uninstall uninstall-am uninstall-pcdataDATA
 
+.PRECIOUS: Makefile
+
 
 install-data-local:
        $(MKDIR_P) $(DESTDIR)$(LXCPATH)
index 8e31bb3..e624356 100644 (file)
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -20,32 +20,63 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
-# serial 1 (pkg-config-0.24)
-# 
-# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
+dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
 AC_DEFUN([PKG_PROG_PKG_CONFIG],
 [m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@@ -67,18 +98,19 @@ if test -n "$PKG_CONFIG"; then
                PKG_CONFIG=""
        fi
 fi[]dnl
-])# PKG_PROG_PKG_CONFIG
+])dnl PKG_PROG_PKG_CONFIG
 
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists.  Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-# only at the first occurence in configure.ac, so if the first place
-# it's called might be skipped (such as if it is within an "if", you
-# have to call PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
 AC_DEFUN([PKG_CHECK_EXISTS],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 if test -n "$PKG_CONFIG" && \
@@ -88,8 +120,10 @@ m4_ifvaln([$3], [else
   $3])dnl
 fi])
 
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
 m4_define([_PKG_CONFIG],
 [if test -n "$$1"; then
     pkg_cv_[]$1="$$1"
@@ -101,10 +135,11 @@ m4_define([_PKG_CONFIG],
  else
     pkg_failed=untried
 fi[]dnl
-])# _PKG_CONFIG
+])dnl _PKG_CONFIG
 
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
 AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -112,19 +147,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 else
         _pkg_short_errors_supported=no
 fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
 
 
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 AC_DEFUN([PKG_CHECK_MODULES],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
@@ -178,9 +211,92 @@ else
         AC_MSG_RESULT([yes])
        $3
 fi[]dnl
-])# PKG_CHECK_MODULES
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
 
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -192,10 +308,10 @@ fi[]dnl
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.14'
+[am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14.1], [],
+m4_if([$1], [1.15], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -211,14 +327,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14.1])dnl
+[AM_AUTOMAKE_VERSION([1.15])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -263,15 +379,14 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 # configured tree to be moved without reconfiguration.
 
 AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 ])
 
 # AM_COND_IF                                            -*- Autoconf -*-
 
-# Copyright (C) 2008-2013 Free Software Foundation, Inc.
+# Copyright (C) 2008-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -308,7 +423,7 @@ fi[]dnl
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -339,7 +454,7 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -530,7 +645,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -606,7 +721,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -696,8 +811,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([AC_PROG_MAKE_SET])dnl
 AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -770,7 +885,11 @@ to "yes", and re-run configure.
 END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
-fi])
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
 dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
@@ -799,7 +918,7 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -810,7 +929,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\    *)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -820,7 +939,7 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -841,7 +960,7 @@ AC_SUBST([am__leading_dot])])
 
 # Check to see how 'make' treats includes.                 -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -891,7 +1010,7 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -930,7 +1049,7 @@ fi
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -959,7 +1078,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1006,7 +1125,7 @@ AC_LANG_POP([C])])
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1241,7 +1360,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
 sys.exit(sys.hexversion < minverhex)"
   AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1260,7 +1379,7 @@ AC_DEFUN([AM_RUN_LOG],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1341,7 +1460,7 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1401,7 +1520,7 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1429,7 +1548,7 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1448,7 +1567,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
index 46c61bb..d613d61 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,13 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am compile \
-       config.guess config.sub install-sh missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -144,6 +153,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in compile config.guess \
+       config.sub install-sh missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -221,6 +232,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -234,6 +246,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -325,6 +338,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -349,7 +363,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -637,6 +650,8 @@ uninstall-am:
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index f02ac93..71dbe15 100644 (file)
@@ -7,6 +7,7 @@ EXTRA_DIST = \
        lxc-containers \
        lxc-generate-aa-rules.py \
        profiles/lxc-default \
+       profiles/lxc-default-cgns \
        profiles/lxc-default-with-mounting \
        profiles/lxc-default-with-nesting \
        usr.bin.lxc-start
@@ -17,19 +18,21 @@ install-apparmor:
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-       $(INSTALL_DATA) abstractions/container-base $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
-       $(INSTALL_DATA) abstractions/start-container $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
-       $(INSTALL_DATA) profiles/lxc-default $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-       $(INSTALL_DATA) profiles/lxc-default-with-mounting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-       $(INSTALL_DATA) profiles/lxc-default-with-nesting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-       $(INSTALL_DATA) lxc-containers $(DESTDIR)$(sysconfdir)/apparmor.d/
-       $(INSTALL_DATA) usr.bin.lxc-start $(DESTDIR)$(sysconfdir)/apparmor.d/
+       $(INSTALL_DATA) $(srcdir)/abstractions/container-base $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
+       $(INSTALL_DATA) $(srcdir)/abstractions/start-container $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
+       $(INSTALL_DATA) $(srcdir)/profiles/lxc-default $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+       $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-cgns $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+       $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-with-mounting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+       $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-with-nesting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+       $(INSTALL_DATA) $(srcdir)/lxc-containers $(DESTDIR)$(sysconfdir)/apparmor.d/
+       $(INSTALL_DATA) $(srcdir)/usr.bin.lxc-start $(DESTDIR)$(sysconfdir)/apparmor.d/
 
 uninstall-apparmor:
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/usr.bin.lxc-start
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc-containers
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-with-nesting
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-with-mounting
+       rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-cgns
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/start-container
        rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/container-base
index 6cde89d..7a54bd8 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,12 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/apparmor
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -108,6 +118,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -160,6 +171,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -173,6 +185,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -264,6 +277,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -281,6 +295,7 @@ EXTRA_DIST = \
        lxc-containers \
        lxc-generate-aa-rules.py \
        profiles/lxc-default \
+       profiles/lxc-default-cgns \
        profiles/lxc-default-with-mounting \
        profiles/lxc-default-with-nesting \
        usr.bin.lxc-start
@@ -300,7 +315,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/apparmor/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/apparmor/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -470,24 +484,28 @@ uninstall-am: uninstall-local
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-local
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_APPARMOR_TRUE@install-apparmor:
 @ENABLE_APPARMOR_TRUE@ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/
 @ENABLE_APPARMOR_TRUE@ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
 @ENABLE_APPARMOR_TRUE@ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) abstractions/container-base $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) abstractions/start-container $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) profiles/lxc-default $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) profiles/lxc-default-with-mounting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) profiles/lxc-default-with-nesting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) lxc-containers $(DESTDIR)$(sysconfdir)/apparmor.d/
-@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) usr.bin.lxc-start $(DESTDIR)$(sysconfdir)/apparmor.d/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/abstractions/container-base $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/abstractions/start-container $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/profiles/lxc-default $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-cgns $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-with-mounting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/profiles/lxc-default-with-nesting $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/lxc-containers $(DESTDIR)$(sysconfdir)/apparmor.d/
+@ENABLE_APPARMOR_TRUE@ $(INSTALL_DATA) $(srcdir)/usr.bin.lxc-start $(DESTDIR)$(sysconfdir)/apparmor.d/
 
 @ENABLE_APPARMOR_TRUE@uninstall-apparmor:
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/usr.bin.lxc-start
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc-containers
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-with-nesting
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-with-mounting
+@ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default-cgns
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/lxc/lxc-default
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/start-container
 @ENABLE_APPARMOR_TRUE@ rm -f $(DESTDIR)$(sysconfdir)/apparmor.d/abstractions/lxc/container-base
index ac8d4e9..c9f5947 100644 (file)
   # allow bind mount of /lib/init/fstab for lxcguest
   mount options=(rw, bind) /lib/init/fstab.lxc/ -> /lib/init/fstab/,
 
+  # allow bind mounts of /run/{,lock} to /var/run/{,lock}
+  mount options=(rw, bind) /run/ -> /var/run/,
+  mount options=(rw, bind) /run/lock/ -> /var/lock/,
+
+  # deny access under /proc/bus to avoid e.g. messing with pci devices directly
+  deny @{PROC}/bus/** wklx,
+
   # deny writes in /proc/sys/fs but allow binfmt_misc to be mounted
   mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,
   deny @{PROC}/sys/fs/** wklx,
   deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/,
   mount fstype=proc -> /proc/,
   mount fstype=sysfs -> /sys/,
+  mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
   deny /sys/firmware/efi/efivars/** rwklx,
   deny /sys/kernel/security/** rwklx,
   mount options=(move) /sys/fs/cgroup/cgmanager/ -> /sys/fs/cgroup/cgmanager.lower/,
+  mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
+
+  # deny reads from debugfs
+  deny /sys/kernel/debug/{,**} rwklx,
 
   # generated by: lxc-generate-aa-rules.py container-rules.base
   deny /proc/sys/[^kn]*{,/**} wklx,
index 235913b..4cd409d 100644 (file)
   # allow bind mount of /lib/init/fstab for lxcguest
   mount options=(rw, bind) /lib/init/fstab.lxc/ -> /lib/init/fstab/,
 
+  # allow bind mounts of /run/{,lock} to /var/run/{,lock}
+  mount options=(rw, bind) /run/ -> /var/run/,
+  mount options=(rw, bind) /run/lock/ -> /var/lock/,
+
+  # deny access under /proc/bus to avoid e.g. messing with pci devices directly
+  deny @{PROC}/bus/** wklx,
+
   # deny writes in /proc/sys/fs but allow binfmt_misc to be mounted
   mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,
   deny @{PROC}/sys/fs/** wklx,
   deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/,
   mount fstype=proc -> /proc/,
   mount fstype=sysfs -> /sys/,
+  mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
   deny /sys/firmware/efi/efivars/** rwklx,
   deny /sys/kernel/security/** rwklx,
   mount options=(move) /sys/fs/cgroup/cgmanager/ -> /sys/fs/cgroup/cgmanager.lower/,
+  mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
+
+  # deny reads from debugfs
+  deny /sys/kernel/debug/{,**} rwklx,
 
index 683f5fc..d7c9a86 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 
 import sys
 
diff --git a/config/apparmor/profiles/lxc-default-cgns b/config/apparmor/profiles/lxc-default-cgns
new file mode 100644 (file)
index 0000000..ff599ef
--- /dev/null
@@ -0,0 +1,12 @@
+# Do not load this file.  Rather, load /etc/apparmor.d/lxc-containers, which
+# will source all profiles under /etc/apparmor.d/lxc
+
+profile lxc-container-default-cgns flags=(attach_disconnected,mediate_deleted) {
+  #include <abstractions/lxc/container-base>
+
+  # the container may never be allowed to mount devpts.  If it does, it
+  # will remount the host's devpts.  We could allow it to do it with
+  # the newinstance option (but, right now, we don't).
+  deny mount fstype=devpts,
+  mount fstype=cgroup -> /sys/fs/cgroup/**,
+}
index 66aa5fd..6e5745f 100644 (file)
@@ -5,12 +5,10 @@ profile lxc-container-default-with-nesting flags=(attach_disconnected,mediate_de
   #include <abstractions/lxc/container-base>
   #include <abstractions/lxc/start-container>
 
-#  Uncomment the line below if you are not using cgmanager
-#  mount fstype=cgroup -> /sys/fs/cgroup/**,
-
   deny /dev/.lxc/proc/** rw,
   deny /dev/.lxc/sys/** rw,
   mount fstype=proc -> /var/cache/lxc/**,
   mount fstype=sysfs -> /var/cache/lxc/**,
   mount options=(rw,bind),
+  mount fstype=cgroup -> /sys/fs/cgroup/**,
 }
index eedde34..f1e6eb9 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,13 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/bash
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc
@@ -109,6 +118,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -161,6 +171,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -174,6 +185,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -265,6 +277,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -289,7 +302,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/bash/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/bash/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -461,6 +473,8 @@ uninstall-am: uninstall-local
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-local
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_BASH_TRUE@install-bash:
 @ENABLE_BASH_TRUE@     $(MKDIR_P) $(DESTDIR)$(sysconfdir)/bash_completion.d/
index ac367e1..2b7b8f1 100644 (file)
@@ -1,4 +1,4 @@
-have lxc-start && {
+_have lxc-start && {
     _lxc_names() {
         COMPREPLY=( $( compgen -W "$( lxc-ls )" "$cur" ) )
     }
@@ -98,6 +98,6 @@ have lxc-start && {
 
     complete -o default -F _lxc_generic_t lxc-create
 
-    complete -o default -F _lxc_generic_o lxc-clone
+    complete -o default -F _lxc_generic_o lxc-copy
     complete -o default -F _lxc_generic_o lxc-start-ephemeral
 }
index cbd1b79..7dcf302 100644 (file)
@@ -1,4 +1,4 @@
-have lxc-start && {
+_have lxc-start && {
     _lxc_names() {
         COMPREPLY=( $( compgen -W "$( lxc-ls )" "$cur" ) )
     }
@@ -98,6 +98,6 @@ have lxc-start && {
 
     complete -o default -F _lxc_generic_t lxc-create
 
-    complete -o default -F _lxc_generic_o lxc-clone
+    complete -o default -F _lxc_generic_o lxc-copy
     complete -o default -F _lxc_generic_o lxc-start-ephemeral
 }
index 531136b..a85b723 100755 (executable)
@@ -3,7 +3,7 @@
 
 scriptversion=2012-10-14.11; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey@cygnus.com>.
 #
 # This program is free software; you can redistribute it and/or modify
index b79252d..1659250 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
 
-timestamp='2013-06-10'
+timestamp='2015-08-20'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@ timestamp='2013-06-10'
 # program.  This Exception is an additional permission under section 7
 # of the GNU General Public License, version 3 ("GPLv3").
 #
-# Originally written by Per Bothner.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
 # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
 #
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
 
 
 me=`echo "$0" | sed -e 's,.*/,,'`
@@ -50,7 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2015 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -149,7 +149,7 @@ Linux|GNU|GNU/*)
        LIBC=gnu
        #endif
        EOF
-       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
        ;;
 esac
 
@@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        # Note: NetBSD doesn't particularly care about the vendor
        # portion of the name.  We always set it to "unknown".
        sysctl="sysctl -n hw.machine_arch"
-       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
-           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+           /sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || \
+           echo unknown)`
        case "${UNAME_MACHINE_ARCH}" in
            armeb) machine=armeb-unknown ;;
            arm*) machine=arm-unknown ;;
            sh3el) machine=shl-unknown ;;
            sh3eb) machine=sh-unknown ;;
            sh5el) machine=sh5le-unknown ;;
+           earmv*)
+               arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+               endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+               machine=${arch}${endian}-unknown
+               ;;
            *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
        esac
        # The Operating System including object format, if it has switched
        # to ELF recently, or will in the future.
        case "${UNAME_MACHINE_ARCH}" in
-           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+           arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
                eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
                        | grep -q __ELF__
@@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
                os=netbsd
                ;;
        esac
+       # Determine ABI tags.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+               abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+               ;;
+       esac
        # The OS release
        # Debian GNU/NetBSD machines have a different userland, and
        # thus, need a distinct triplet. However, they do not need
@@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
                release='-gnu'
                ;;
            *)
-               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
                ;;
        esac
        # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
        # contains redundant information, the shorter form:
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "${machine}-${os}${release}"
+       echo "${machine}-${os}${release}${abi}"
        exit ;;
     *:Bitrig:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -235,6 +249,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:MirBSD:*:*)
        echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
        exit ;;
+    *:Sortix:*:*)
+       echo ${UNAME_MACHINE}-unknown-sortix
+       exit ;;
     alpha:OSF1:*:*)
        case $UNAME_RELEASE in
        *4.0)
@@ -579,8 +596,9 @@ EOF
        else
                IBM_ARCH=powerpc
        fi
-       if [ -x /usr/bin/oslevel ] ; then
-               IBM_REV=`/usr/bin/oslevel`
+       if [ -x /usr/bin/lslpp ] ; then
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
        else
                IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
        fi
@@ -826,7 +844,7 @@ EOF
     *:MINGW*:*)
        echo ${UNAME_MACHINE}-pc-mingw32
        exit ;;
-    i*:MSYS*:*)
+    *:MSYS*:*)
        echo ${UNAME_MACHINE}-pc-msys
        exit ;;
     i*:windows32*:*)
@@ -932,6 +950,9 @@ EOF
     crisv32:Linux:*:*)
        echo ${UNAME_MACHINE}-axis-linux-${LIBC}
        exit ;;
+    e2k:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
     frv:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
@@ -969,10 +990,10 @@ EOF
        eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
        test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
        ;;
-    or1k:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    openrisc*:Linux:*:*)
+       echo or1k-unknown-linux-${LIBC}
        exit ;;
-    or32:Linux:*:*)
+    or32:Linux:*:* | or1k*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
     padre:Linux:*:*)
@@ -1020,7 +1041,7 @@ EOF
        echo ${UNAME_MACHINE}-dec-linux-${LIBC}
        exit ;;
     x86_64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
        exit ;;
     xtensa*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1260,16 +1281,26 @@ EOF
        if test "$UNAME_PROCESSOR" = unknown ; then
            UNAME_PROCESSOR=powerpc
        fi
-       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-           if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-               grep IS_64BIT_ARCH >/dev/null
-           then
-               case $UNAME_PROCESSOR in
-                   i386) UNAME_PROCESSOR=x86_64 ;;
-                   powerpc) UNAME_PROCESSOR=powerpc64 ;;
-               esac
+       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                   grep IS_64BIT_ARCH >/dev/null
+               then
+                   case $UNAME_PROCESSOR in
+                       i386) UNAME_PROCESSOR=x86_64 ;;
+                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
+                   esac
+               fi
            fi
+       elif test "$UNAME_PROCESSOR" = i386 ; then
+           # Avoid executing cc on OS X 10.9, as it ships with a stub
+           # that puts up a graphical alert prompting to install
+           # developer tools.  Any system running Mac OS X 10.7 or
+           # later (Darwin 11 and later) is required to have a 64-bit
+           # processor. This is not true of the ARM version of Darwin
+           # that Apple uses in portable devices.
+           UNAME_PROCESSOR=x86_64
        fi
        echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
        exit ;;
@@ -1361,154 +1392,6 @@ EOF
        exit ;;
 esac
 
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-       "4"
-#else
-       ""
-#endif
-       ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-       printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-       printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
-       { echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-       echo c1-convex-bsd
-       exit ;;
-    c2*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-       exit ;;
-    c34*)
-       echo c34-convex-bsd
-       exit ;;
-    c38*)
-       echo c38-convex-bsd
-       exit ;;
-    c4*)
-       echo c4-convex-bsd
-       exit ;;
-    esac
-fi
-
 cat >&2 <<EOF
 $0: unable to guess system type
 
index 9633db7..1acc966 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
 
-timestamp='2013-08-10'
+timestamp='2015-08-20'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ timestamp='2013-08-10'
 # of the GNU General Public License, version 3 ("GPLv3").
 
 
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -68,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2015 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +117,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
   linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-  knetbsd*-gnu* | netbsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
   kopensolaris*-gnu* | \
   storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
@@ -255,16 +255,18 @@ case $basic_machine in
        | arc | arceb \
        | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
        | avr | avr32 \
+       | ba \
        | be32 | be64 \
        | bfin \
        | c4x | c8051 | clipper \
        | d10v | d30v | dlx | dsp16xx \
-       | epiphany \
-       | fido | fr30 | frv \
+       | e2k | epiphany \
+       | fido | fr30 | frv | ft32 \
        | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
        | hexagon \
        | i370 | i860 | i960 | ia64 \
        | ip2k | iq2000 \
+       | k1om \
        | le32 | le64 \
        | lm32 \
        | m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -282,8 +284,10 @@ case $basic_machine in
        | mips64vr5900 | mips64vr5900el \
        | mipsisa32 | mipsisa32el \
        | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa32r6 | mipsisa32r6el \
        | mipsisa64 | mipsisa64el \
        | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64r6 | mipsisa64r6el \
        | mipsisa64sb1 | mipsisa64sb1el \
        | mipsisa64sr71k | mipsisa64sr71kel \
        | mipsr5900 | mipsr5900el \
@@ -295,14 +299,14 @@ case $basic_machine in
        | nds32 | nds32le | nds32be \
        | nios | nios2 | nios2eb | nios2el \
        | ns16k | ns32k \
-       | open8 \
-       | or1k | or32 \
+       | open8 | or1k | or1knd | or32 \
        | pdp10 | pdp11 | pj | pjl \
        | powerpc | powerpc64 | powerpc64le | powerpcle \
        | pyramid \
+       | riscv32 | riscv64 \
        | rl78 | rx \
        | score \
-       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
        | sh64 | sh64le \
        | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
        | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -310,6 +314,7 @@ case $basic_machine in
        | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
        | ubicom32 \
        | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+       | visium \
        | we32k \
        | x86 | xc16x | xstormy16 | xtensa \
        | z8k | z80)
@@ -324,7 +329,10 @@ case $basic_machine in
        c6x)
                basic_machine=tic6x-unknown
                ;;
-       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+       leon|leon[3-9])
+               basic_machine=sparc-$basic_machine
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
                basic_machine=$basic_machine-unknown
                os=-none
                ;;
@@ -369,18 +377,20 @@ case $basic_machine in
        | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
        | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
        | avr-* | avr32-* \
+       | ba-* \
        | be32-* | be64-* \
        | bfin-* | bs2000-* \
        | c[123]* | c30-* | [cjt]90-* | c4x-* \
        | c8051-* | clipper-* | craynv-* | cydra-* \
        | d10v-* | d30v-* | dlx-* \
-       | elxsi-* \
+       | e2k-* | elxsi-* \
        | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
        | h8300-* | h8500-* \
        | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
        | hexagon-* \
        | i*86-* | i860-* | i960-* | ia64-* \
        | ip2k-* | iq2000-* \
+       | k1om-* \
        | le32-* | le64-* \
        | lm32-* \
        | m32c-* | m32r-* | m32rle-* \
@@ -400,8 +410,10 @@ case $basic_machine in
        | mips64vr5900-* | mips64vr5900el-* \
        | mipsisa32-* | mipsisa32el-* \
        | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa32r6-* | mipsisa32r6el-* \
        | mipsisa64-* | mipsisa64el-* \
        | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64r6-* | mipsisa64r6el-* \
        | mipsisa64sb1-* | mipsisa64sb1el-* \
        | mipsisa64sr71k-* | mipsisa64sr71kel-* \
        | mipsr5900-* | mipsr5900el-* \
@@ -413,16 +425,18 @@ case $basic_machine in
        | nios-* | nios2-* | nios2eb-* | nios2el-* \
        | none-* | np1-* | ns16k-* | ns32k-* \
        | open8-* \
+       | or1k*-* \
        | orion-* \
        | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
        | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
        | pyramid-* \
+       | riscv32-* | riscv64-* \
        | rl78-* | romp-* | rs6000-* | rx-* \
        | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
        | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
        | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
        | sparclite-* \
-       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
        | tahoe-* \
        | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
        | tile*-* \
@@ -430,6 +444,7 @@ case $basic_machine in
        | ubicom32-* \
        | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
        | vax-* \
+       | visium-* \
        | we32k-* \
        | x86-* | x86_64-* | xc16x-* | xps100-* \
        | xstormy16-* | xtensa*-* \
@@ -506,6 +521,9 @@ case $basic_machine in
                basic_machine=i386-pc
                os=-aros
                ;;
+        asmjs)
+               basic_machine=asmjs-unknown
+               ;;
        aux)
                basic_machine=m68k-apple
                os=-aux
@@ -767,6 +785,9 @@ case $basic_machine in
                basic_machine=m68k-isi
                os=-sysv
                ;;
+       leon-*|leon[3-9]-*)
+               basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+               ;;
        m68knommu)
                basic_machine=m68k-unknown
                os=-linux
@@ -822,6 +843,10 @@ case $basic_machine in
                basic_machine=powerpc-unknown
                os=-morphos
                ;;
+       moxiebox)
+               basic_machine=moxie-unknown
+               os=-moxiebox
+               ;;
        msdos)
                basic_machine=i386-pc
                os=-msdos
@@ -1354,7 +1379,7 @@ case $os in
              | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
              | -sym* | -kopensolaris* | -plan9* \
              | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* | -aros* \
+             | -aos* | -aros* | -cloudabi* | -sortix* \
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
              | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
@@ -1367,14 +1392,14 @@ case $os in
              | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
              | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
              | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-             | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
              | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
              | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
              | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
              | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
@@ -1592,9 +1617,6 @@ case $basic_machine in
        mips*-*)
                os=-elf
                ;;
-       or1k-*)
-               os=-elf
-               ;;
        or32-*)
                os=-coff
                ;;
index 4ebd5b3..fc98710 100755 (executable)
@@ -3,7 +3,7 @@
 
 scriptversion=2013-05-30.07; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
index 39c5439..4042124 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/etc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = default.conf
@@ -138,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(configdir)"
 DATA = $(config_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -320,7 +334,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/etc/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/etc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -513,6 +526,8 @@ uninstall-am: uninstall-configDATA
        mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \
        uninstall-am uninstall-configDATA
 
+.PRECIOUS: Makefile
+
 
 distclean-local:
        @$(RM) -f default.conf
index aa4a9e3..4363dc7 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,12 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/init
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -143,6 +153,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -220,6 +231,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -233,6 +245,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -324,6 +337,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -348,7 +362,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/init/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/init/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -636,6 +649,8 @@ uninstall-am:
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 8c0134c..123e800 100644 (file)
@@ -1,2 +1,2 @@
-EXTRA_DIST = lxc-containers.in lxc-net.in
-pkglibexec_SCRIPTS = lxc-containers lxc-net
+EXTRA_DIST = lxc-containers.in lxc-net.in lxc-devsetup
+pkglibexec_SCRIPTS = lxc-containers lxc-net lxc-devsetup
index 692f0d2..9898a3e 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,13 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/init/common
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-containers.in $(srcdir)/lxc-net.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-containers lxc-net
@@ -139,6 +148,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-containers.in \
+       $(srcdir)/lxc-net.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -191,6 +202,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -204,6 +216,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -295,6 +308,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -303,8 +317,8 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = lxc-containers.in lxc-net.in
-pkglibexec_SCRIPTS = lxc-containers lxc-net
+EXTRA_DIST = lxc-containers.in lxc-net.in lxc-devsetup
+pkglibexec_SCRIPTS = lxc-containers lxc-net lxc-devsetup
 all: all-am
 
 .SUFFIXES:
@@ -320,7 +334,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/init/common/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/init/common/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -531,6 +544,8 @@ uninstall-am: uninstall-pkglibexecSCRIPTS
        mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \
        uninstall-am uninstall-pkglibexecSCRIPTS
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index efe64c1..d457e78 100644 (file)
@@ -124,7 +124,13 @@ start() {
         fi
     done
 
-    dnsmasq $LXC_DHCP_CONFILE_ARG $LXC_DOMAIN_ARG -u ${DNSMASQ_USER} --strict-order --bind-interfaces --pid-file="${varrun}"/dnsmasq.pid --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile="${varlib}"/misc/dnsmasq.${LXC_BRIDGE}.leases --dhcp-authoritative $LXC_IPV6_ARG || cleanup
+    dnsmasq $LXC_DHCP_CONFILE_ARG $LXC_DOMAIN_ARG -u ${DNSMASQ_USER} \
+            --strict-order --bind-interfaces --pid-file="${varrun}"/dnsmasq.pid \
+            --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} \
+            --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override \
+            --except-interface=lo --interface=${LXC_BRIDGE} \
+            --dhcp-leasefile="${varlib}"/misc/dnsmasq.${LXC_BRIDGE}.leases \
+            --dhcp-authoritative $LXC_IPV6_ARG || cleanup
 
     touch "${varrun}"/network_up
     FAILED=0
index 4201d98..c448850 100644 (file)
@@ -1,22 +1,23 @@
 EXTRA_DIST = \
-       lxc-devsetup \
        lxc-apparmor-load \
        lxc.service.in \
+       lxc@.service.in \
        lxc-net.service.in
 
 if INIT_SCRIPT_SYSTEMD
-BUILT_SOURCES = lxc.service lxc-net.service
+BUILT_SOURCES = lxc.service lxc@.service lxc-net.service
 
-install-systemd: lxc.service lxc-net.service lxc-devsetup lxc-apparmor-load
+install-systemd: lxc.service lxc@.service lxc-net.service lxc-apparmor-load
        $(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
-       $(INSTALL_DATA) lxc.service lxc-net.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
+       $(INSTALL_DATA) lxc.service lxc@.service lxc-net.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
 
 uninstall-systemd:
        rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc.service
+       rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc@.service
        rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc-net.service
        rmdir $(DESTDIR)$(SYSTEMD_UNIT_DIR) || :
 
-pkglibexec_SCRIPTS = lxc-devsetup lxc-apparmor-load
+pkglibexec_SCRIPTS = lxc-apparmor-load
 
 install-data-local: install-systemd
 uninstall-local: uninstall-systemd
index 9bf34d6..c8a7927 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,16 +89,15 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/init/systemd
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc.service.in $(srcdir)/lxc-net.service.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
-CONFIG_CLEAN_FILES = lxc.service lxc-net.service
+CONFIG_CLEAN_FILES = lxc.service lxc@.service lxc-net.service
 CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -139,6 +148,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-net.service.in \
+       $(srcdir)/lxc.service.in $(srcdir)/lxc@.service.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -191,6 +202,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -204,6 +216,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -295,6 +308,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -304,13 +318,13 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 EXTRA_DIST = \
-       lxc-devsetup \
        lxc-apparmor-load \
        lxc.service.in \
+       lxc@.service.in \
        lxc-net.service.in
 
-@INIT_SCRIPT_SYSTEMD_TRUE@BUILT_SOURCES = lxc.service lxc-net.service
-@INIT_SCRIPT_SYSTEMD_TRUE@pkglibexec_SCRIPTS = lxc-devsetup lxc-apparmor-load
+@INIT_SCRIPT_SYSTEMD_TRUE@BUILT_SOURCES = lxc.service lxc@.service lxc-net.service
+@INIT_SCRIPT_SYSTEMD_TRUE@pkglibexec_SCRIPTS = lxc-apparmor-load
 all: $(BUILT_SOURCES)
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -327,7 +341,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/init/systemd/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/init/systemd/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -347,6 +360,8 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 $(am__aclocal_m4_deps):
 lxc.service: $(top_builddir)/config.status $(srcdir)/lxc.service.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc@.service: $(top_builddir)/config.status $(srcdir)/lxc@.service.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-net.service: $(top_builddir)/config.status $(srcdir)/lxc-net.service.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 install-pkglibexecSCRIPTS: $(pkglibexec_SCRIPTS)
@@ -544,13 +559,16 @@ uninstall-am: uninstall-local uninstall-pkglibexecSCRIPTS
        uninstall uninstall-am uninstall-local \
        uninstall-pkglibexecSCRIPTS
 
+.PRECIOUS: Makefile
+
 
-@INIT_SCRIPT_SYSTEMD_TRUE@install-systemd: lxc.service lxc-net.service lxc-devsetup lxc-apparmor-load
+@INIT_SCRIPT_SYSTEMD_TRUE@install-systemd: lxc.service lxc@.service lxc-net.service lxc-apparmor-load
 @INIT_SCRIPT_SYSTEMD_TRUE@     $(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
-@INIT_SCRIPT_SYSTEMD_TRUE@     $(INSTALL_DATA) lxc.service lxc-net.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
+@INIT_SCRIPT_SYSTEMD_TRUE@     $(INSTALL_DATA) lxc.service lxc@.service lxc-net.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
 
 @INIT_SCRIPT_SYSTEMD_TRUE@uninstall-systemd:
 @INIT_SCRIPT_SYSTEMD_TRUE@     rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc.service
+@INIT_SCRIPT_SYSTEMD_TRUE@     rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc@.service
 @INIT_SCRIPT_SYSTEMD_TRUE@     rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc-net.service
 @INIT_SCRIPT_SYSTEMD_TRUE@     rmdir $(DESTDIR)$(SYSTEMD_UNIT_DIR) || :
 
diff --git a/config/init/systemd/lxc@.service.in b/config/init/systemd/lxc@.service.in
new file mode 100644 (file)
index 0000000..190280e
--- /dev/null
@@ -0,0 +1,20 @@
+[Unit]
+Description=LXC Container: %i
+# This pulls in apparmor, dev-setup, lxc-net
+After=lxc.service
+Wants=lxc.service
+
+[Service]
+Type=simple
+KillMode=mixed
+KillSignal=SIGPWR
+TimeoutStopSec=120s
+ExecStart=@BINDIR@/lxc-start -n %i
+# Environment=BOOTUP=serial
+# Environment=CONSOLETYPE=serial
+Delegate=yes
+StandardOutput=syslog
+StandardError=syslog
+
+[Install]
+WantedBy=multi-user.target
index 7a140d7..1834eff 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,13 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/init/sysvinit
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-containers.in $(srcdir)/lxc-net.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-containers lxc-net
@@ -109,6 +118,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-containers.in \
+       $(srcdir)/lxc-net.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -161,6 +172,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -174,6 +186,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -265,6 +278,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -294,7 +308,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/init/sysvinit/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/init/sysvinit/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -468,6 +481,8 @@ uninstall-am: uninstall-local
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-local
 
+.PRECIOUS: Makefile
+
 
 @INIT_SCRIPT_SYSV_TRUE@install-sysvinit: lxc-containers lxc-net
 @INIT_SCRIPT_SYSV_TRUE@        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/$(initdir)
index bc93322..7a55c3b 100644 (file)
@@ -30,6 +30,8 @@ if ! type action >/dev/null 2>&1; then
 fi
 
 start() {
+    # Setup host /dev for autodev containers.
+    @LIBEXECDIR@/lxc/lxc-devsetup
     action $"Starting LXC autoboot containers: " @LIBEXECDIR@/lxc/lxc-containers start
 }
 
index 916b850..5552d32 100644 (file)
@@ -4,7 +4,7 @@ if INIT_SCRIPT_UPSTART
 install-upstart: lxc.conf lxc-instance.conf lxc-net.conf
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/init/
        $(INSTALL_DATA) lxc.conf $(DESTDIR)$(sysconfdir)/init/
-       $(INSTALL_DATA) lxc-instance.conf $(DESTDIR)$(sysconfdir)/init/
+       $(INSTALL_DATA) $(srcdir)/lxc-instance.conf $(DESTDIR)$(sysconfdir)/init/
        $(INSTALL_DATA) lxc-net.conf $(DESTDIR)$(sysconfdir)/init/
 
 uninstall-upstart:
index 3b31bbe..155d28d 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,16 +88,15 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/init/upstart
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-net.conf.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
-CONFIG_CLEAN_FILES = lxc-net.conf
+CONFIG_CLEAN_FILES = lxc.conf lxc-net.conf
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -109,6 +118,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-net.conf.in \
+       $(srcdir)/lxc.conf.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -161,6 +172,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -174,6 +186,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -265,6 +278,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -289,7 +303,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/init/upstart/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/init/upstart/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -307,6 +320,8 @@ $(top_srcdir)/configure:  $(am__configure_deps)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
        cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
+lxc.conf: $(top_builddir)/config.status $(srcdir)/lxc.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-net.conf: $(top_builddir)/config.status $(srcdir)/lxc-net.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 tags TAGS:
@@ -380,8 +395,8 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-@INIT_SCRIPT_UPSTART_FALSE@install-data-local:
 @INIT_SCRIPT_UPSTART_FALSE@uninstall-local:
+@INIT_SCRIPT_UPSTART_FALSE@install-data-local:
 clean: clean-am
 
 clean-am: clean-generic mostlyclean-am
@@ -461,11 +476,13 @@ uninstall-am: uninstall-local
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-local
 
+.PRECIOUS: Makefile
+
 
 @INIT_SCRIPT_UPSTART_TRUE@install-upstart: lxc.conf lxc-instance.conf lxc-net.conf
 @INIT_SCRIPT_UPSTART_TRUE@     $(MKDIR_P) $(DESTDIR)$(sysconfdir)/init/
 @INIT_SCRIPT_UPSTART_TRUE@     $(INSTALL_DATA) lxc.conf $(DESTDIR)$(sysconfdir)/init/
-@INIT_SCRIPT_UPSTART_TRUE@     $(INSTALL_DATA) lxc-instance.conf $(DESTDIR)$(sysconfdir)/init/
+@INIT_SCRIPT_UPSTART_TRUE@     $(INSTALL_DATA) $(srcdir)/lxc-instance.conf $(DESTDIR)$(sysconfdir)/init/
 @INIT_SCRIPT_UPSTART_TRUE@     $(INSTALL_DATA) lxc-net.conf $(DESTDIR)$(sysconfdir)/init/
 
 @INIT_SCRIPT_UPSTART_TRUE@uninstall-upstart:
index 437db3c..c48b9ca 100644 (file)
@@ -45,6 +45,9 @@ pre-start script
                fi
        fi
 
+       # Setup host /dev for autodev containers.
+       /usr/local/libexec/lxc/lxc-devsetup
+
        [ "x$LXC_AUTO" = "xtrue" ] || exit 0
 
        if [ -n "$BOOTGROUPS" ]
diff --git a/config/init/upstart/lxc.conf.in b/config/init/upstart/lxc.conf.in
new file mode 100644 (file)
index 0000000..899fe11
--- /dev/null
@@ -0,0 +1,77 @@
+description "lxc"
+author "Serge Hallyn <serge.hallyn@canonical.com>"
+
+start on runlevel [2345]
+stop on starting rc RUNLEVEL=[016]
+
+env LXC_AUTO="false"
+
+# These can be overridden in /etc/default/lxc
+
+# BOOTGROUPS - What groups should start on bootup?
+#      Comma separated list of groups.
+#      Leading comma, trailing comma or embedded double
+#      comma indicates when the NULL group should be run.
+# Example (default): boot the onboot group first then the NULL group
+env BOOTGROUPS="onboot,"
+
+# SHUTDOWNDELAY - Wait time for a container to shut down.
+#      Container shutdown can result in lengthy system
+#      shutdown times.  Even 5 seconds per container can be
+#      too long.
+env SHUTDOWNDELAY=5
+
+# OPTIONS can be used for anything else.
+#      If you want to boot everything then
+#      options can be "-a" or "-a -A".
+env OPTIONS=
+
+# STOPOPTS are stop options.  The can be used for anything else to stop.
+#      If you want to kill containers fast, use -k
+env STOPOPTS="-a -A -s"
+
+pre-start script
+       [ -f /etc/default/lxc ] && . /etc/default/lxc
+
+       # don't load profiles if mount mediation is not supported
+       SYSF=/sys/kernel/security/apparmor/features/mount/mask
+       if [ -f $SYSF ]; then
+               if [ -x /lib/apparmor/profile-load ]; then
+                       /lib/apparmor/profile-load usr.bin.lxc-start
+                       /lib/apparmor/profile-load lxc-containers
+               elif [ -x /lib/init/apparmor-profile-load ]; then
+                       /lib/init/apparmor-profile-load usr.bin.lxc-start
+                       /lib/init/apparmor-profile-load lxc-containers
+               fi
+       fi
+
+       # Setup host /dev for autodev containers.
+       @LIBEXECDIR@/lxc/lxc-devsetup
+
+       [ "x$LXC_AUTO" = "xtrue" ] || exit 0
+
+       if [ -n "$BOOTGROUPS" ]
+       then
+               BOOTGROUPS="-g $BOOTGROUPS"
+       fi
+
+       # Process the "onboot" group first then the NULL group.
+       lxc-autostart -L $OPTIONS $BOOTGROUPS | while read line; do
+               set -- $line
+               (start lxc-instance NAME=$1 && sleep $2) || true
+       done
+end script
+
+# The stop is serialized and can take excessive time.  We need to avoid
+# delaying the system shutdown / reboot as much as we can since it's not
+# parallelized...  Even 5 second timout may be too long.
+post-stop script
+       [ -f /etc/default/lxc ] && . /etc/default/lxc
+
+       if [ -n "$SHUTDOWNDELAY" ]
+       then
+               SHUTDOWNDELAY="-t $SHUTDOWNDELAY"
+       fi
+
+       lxc-autostart $STOPOPTS $SHUTDOWNDELAY || true
+end script
index 377bb86..59990a1 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2011-11-20.07; # UTC
+scriptversion=2014-09-12.12; # UTC
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
@@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
 # This script is compatible with the BSD install script, but was written
 # from scratch.
 
+tab='  '
 nl='
 '
-IFS=" ""       $nl"
+IFS=" $tab$nl"
 
-# set DOITPROG to echo to test this script
+# Set DOITPROG to "echo" to test this script.
 
-# Don't use :- since 4.3BSD and earlier shells don't like it.
 doit=${DOITPROG-}
-if test -z "$doit"; then
-  doit_exec=exec
-else
-  doit_exec=$doit
-fi
+doit_exec=${doit:-exec}
 
 # Put in absolute file names if you don't have them in your path;
 # or use environment vars.
@@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
 rmprog=${RMPROG-rm}
 stripprog=${STRIPPROG-strip}
 
-posix_glob='?'
-initialize_posix_glob='
-  test "$posix_glob" != "?" || {
-    if (set -f) 2>/dev/null; then
-      posix_glob=
-    else
-      posix_glob=:
-    fi
-  }
-'
-
 posix_mkdir=
 
 # Desired mode of installed file.
@@ -97,7 +82,7 @@ dir_arg=
 dst_arg=
 
 copy_on_change=false
-no_target_directory=
+is_target_a_directory=possibly
 
 usage="\
 Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -137,46 +122,57 @@ while test $# -ne 0; do
     -d) dir_arg=true;;
 
     -g) chgrpcmd="$chgrpprog $2"
-       shift;;
+        shift;;
 
     --help) echo "$usage"; exit $?;;
 
     -m) mode=$2
-       case $mode in
-         *' '* | *'    '* | *'
-'*       | *'*'* | *'?'* | *'['*)
-           echo "$0: invalid mode: $mode" >&2
-           exit 1;;
-       esac
-       shift;;
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
 
     -o) chowncmd="$chownprog $2"
-       shift;;
+        shift;;
 
     -s) stripcmd=$stripprog;;
 
-    -t) dst_arg=$2
-       # Protect names problematic for 'test' and other utilities.
-       case $dst_arg in
-         -* | [=\(\)!]) dst_arg=./$dst_arg;;
-       esac
-       shift;;
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
 
-    -T) no_target_directory=true;;
+    -T) is_target_a_directory=never;;
 
     --version) echo "$0 $scriptversion"; exit $?;;
 
-    --)        shift
-       break;;
+    --) shift
+        break;;
 
-    -*)        echo "$0: invalid option: $1" >&2
-       exit 1;;
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
 
     *)  break;;
   esac
   shift
 done
 
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
 if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
   # When -d is used, all remaining arguments are directories to create.
   # When -t is used, the destination is already specified.
@@ -208,6 +204,15 @@ if test $# -eq 0; then
 fi
 
 if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
+if test -z "$dir_arg"; then
   do_exit='(exit $ret); exit $ret'
   trap "ret=129; $do_exit" 1
   trap "ret=130; $do_exit" 2
@@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
 
     *[0-7])
       if test -z "$stripcmd"; then
-       u_plus_rw=
+        u_plus_rw=
       else
-       u_plus_rw='% 200'
+        u_plus_rw='% 200'
       fi
       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
     *)
       if test -z "$stripcmd"; then
-       u_plus_rw=
+        u_plus_rw=
       else
-       u_plus_rw=,u+rw
+        u_plus_rw=,u+rw
       fi
       cp_umask=$mode$u_plus_rw;;
   esac
@@ -269,41 +274,15 @@ do
     # If destination is a directory, append the input filename; won't work
     # if double slashes aren't ignored.
     if test -d "$dst"; then
-      if test -n "$no_target_directory"; then
-       echo "$0: $dst_arg: Is a directory" >&2
-       exit 1
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
       fi
       dstdir=$dst
       dst=$dstdir/`basename "$src"`
       dstdir_status=0
     else
-      # Prefer dirname, but fall back on a substitute if dirname fails.
-      dstdir=`
-       (dirname "$dst") 2>/dev/null ||
-       expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-            X"$dst" : 'X\(//\)[^/]' \| \
-            X"$dst" : 'X\(//\)$' \| \
-            X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
-       echo X"$dst" |
-           sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-                  s//\1/
-                  q
-                }
-                /^X\(\/\/\)[^/].*/{
-                  s//\1/
-                  q
-                }
-                /^X\(\/\/\)$/{
-                  s//\1/
-                  q
-                }
-                /^X\(\/\).*/{
-                  s//\1/
-                  q
-                }
-                s/.*/./; q'
-      `
-
+      dstdir=`dirname "$dst"`
       test -d "$dstdir"
       dstdir_status=$?
     fi
@@ -314,74 +293,81 @@ do
   if test $dstdir_status != 0; then
     case $posix_mkdir in
       '')
-       # Create intermediate dirs using mode 755 as modified by the umask.
-       # This is like FreeBSD 'install' as of 1997-10-28.
-       umask=`umask`
-       case $stripcmd.$umask in
-         # Optimize common cases.
-         *[2367][2367]) mkdir_umask=$umask;;
-         .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
-         *[0-7])
-           mkdir_umask=`expr $umask + 22 \
-             - $umask % 100 % 40 + $umask % 20 \
-             - $umask % 10 % 4 + $umask % 2
-           `;;
-         *) mkdir_umask=$umask,go-w;;
-       esac
-
-       # With -d, create the new directory with the user-specified mode.
-       # Otherwise, rely on $mkdir_umask.
-       if test -n "$dir_arg"; then
-         mkdir_mode=-m$mode
-       else
-         mkdir_mode=
-       fi
-
-       posix_mkdir=false
-       case $umask in
-         *[123567][0-7][0-7])
-           # POSIX mkdir -p sets u+wx bits regardless of umask, which
-           # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-           ;;
-         *)
-           tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-           trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
-           if (umask $mkdir_umask &&
-               exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
-           then
-             if test -z "$dir_arg" || {
-                  # Check for POSIX incompatibilities with -m.
-                  # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-                  # other-writable bit of parent directory when it shouldn't.
-                  # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-                  ls_ld_tmpdir=`ls -ld "$tmpdir"`
-                  case $ls_ld_tmpdir in
-                    d????-?r-*) different_mode=700;;
-                    d????-?--*) different_mode=755;;
-                    *) false;;
-                  esac &&
-                  $mkdirprog -m$different_mode -p -- "$tmpdir" && {
-                    ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
-                    test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-                  }
-                }
-             then posix_mkdir=:
-             fi
-             rmdir "$tmpdir/d" "$tmpdir"
-           else
-             # Remove any dirs left behind by ancient mkdir implementations.
-             rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
-           fi
-           trap '' 0;;
-       esac;;
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            # $RANDOM is not portable (e.g. dash);  use it when possible to
+            # lower collision chance
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
+            # create the $tmpdir first (and fail if unsuccessful) to make sure
+            # that nobody tries to guess the $tmpdir name.
+            if (umask $mkdir_umask &&
+                $mkdirprog $mkdir_mode "$tmpdir" &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   test_tmpdir="$tmpdir/a"
+                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
     esac
 
     if
       $posix_mkdir && (
-       umask $mkdir_umask &&
-       $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
       )
     then :
     else
@@ -391,53 +377,51 @@ do
       # directory the slow way, step by step, checking for races as we go.
 
       case $dstdir in
-       /*) prefix='/';;
-       [-=\(\)!]*) prefix='./';;
-       *)  prefix='';;
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
       esac
 
-      eval "$initialize_posix_glob"
-
       oIFS=$IFS
       IFS=/
-      $posix_glob set -f
+      set -f
       set fnord $dstdir
       shift
-      $posix_glob set +f
+      set +f
       IFS=$oIFS
 
       prefixes=
 
       for d
       do
-       test X"$d" = X && continue
-
-       prefix=$prefix$d
-       if test -d "$prefix"; then
-         prefixes=
-       else
-         if $posix_mkdir; then
-           (umask=$mkdir_umask &&
-            $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
-           # Don't fail if two instances are running concurrently.
-           test -d "$prefix" || exit 1
-         else
-           case $prefix in
-             *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
-             *) qprefix=$prefix;;
-           esac
-           prefixes="$prefixes '$qprefix'"
-         fi
-       fi
-       prefix=$prefix/
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
       done
 
       if test -n "$prefixes"; then
-       # Don't fail if two instances are running concurrently.
-       (umask $mkdir_umask &&
-        eval "\$doit_exec \$mkdirprog $prefixes") ||
-         test -d "$dstdir" || exit 1
-       obsolete_mkdir_used=true
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
       fi
     fi
   fi
@@ -472,15 +456,12 @@ do
 
     # If -C, don't bother to copy if it wouldn't change the file.
     if $copy_on_change &&
-       old=`LC_ALL=C ls -dlL "$dst"    2>/dev/null` &&
-       new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
-
-       eval "$initialize_posix_glob" &&
-       $posix_glob set -f &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
        set X $old && old=:$2:$4:$5:$6 &&
        set X $new && new=:$2:$4:$5:$6 &&
-       $posix_glob set +f &&
-
+       set +f &&
        test "$old" = "$new" &&
        $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
     then
@@ -493,24 +474,24 @@ do
       # to itself, or perhaps because mv is so ancient that it does not
       # support -f.
       {
-       # Now remove or move aside any old file at destination location.
-       # We try this two ways since rm can't unlink itself on some
-       # systems and the destination file might be busy for other
-       # reasons.  In this case, the final cleanup might fail but the new
-       # file should still install successfully.
-       {
-         test ! -f "$dst" ||
-         $doit $rmcmd -f "$dst" 2>/dev/null ||
-         { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-           { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
-         } ||
-         { echo "$0: cannot unlink or rename $dst" >&2
-           (exit 1); exit 1
-         }
-       } &&
-
-       # Now rename the file to the real destination.
-       $doit $mvcmd "$dsttmp" "$dst"
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
       }
     fi || exit 1
 
index db98974..f62bbae 100755 (executable)
@@ -3,7 +3,7 @@
 
 scriptversion=2013-10-28.13; # UTC
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
index ddb020b..334989d 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/selinux
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -138,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(selinuxdir)"
 DATA = $(selinux_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -325,7 +339,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/selinux/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/selinux/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -518,6 +531,8 @@ uninstall-am: uninstall-selinuxDATA
        pdf-am ps ps-am tags-am uninstall uninstall-am \
        uninstall-selinuxDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 0dc4497..77e1231 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,13 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/sysconfig
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc
@@ -139,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(sysconfigdir)"
 DATA = $(sysconfig_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -191,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -204,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -295,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -323,7 +336,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/sysconfig/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/sysconfig/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -518,6 +530,8 @@ uninstall-am: uninstall-sysconfigDATA
        pdf-am ps ps-am tags-am uninstall uninstall-am \
        uninstall-sysconfigDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index e587899..1a50f62 100644 (file)
@@ -5,6 +5,8 @@ EXTRA_DIST = common.seccomp
 SUBDIRS = common.conf.d
 
 templatesconfig_DATA = \
+       alpine.common.conf \
+       alpine.userns.conf \
        archlinux.common.conf \
        archlinux.userns.conf \
        centos.common.conf \
@@ -25,6 +27,8 @@ templatesconfig_DATA = \
        oracle.userns.conf \
        plamo.common.conf \
        plamo.userns.conf \
+       slackware.common.conf \
+       slackware.userns.conf \
        ubuntu-cloud.common.conf \
        ubuntu-cloud.lucid.conf \
        ubuntu-cloud.userns.conf \
@@ -32,4 +36,6 @@ templatesconfig_DATA = \
        ubuntu.lucid.conf \
        ubuntu.userns.conf \
        openwrt.common.conf \
+       sparclinux.common.conf \
+       sparclinux.userns.conf \
        userns.conf
index 1c8e192..1536396 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,46 +89,26 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/templates
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/archlinux.common.conf.in \
-       $(srcdir)/archlinux.userns.conf.in \
-       $(srcdir)/centos.common.conf.in \
-       $(srcdir)/centos.userns.conf.in $(srcdir)/common.conf.in \
-       $(srcdir)/debian.common.conf.in \
-       $(srcdir)/debian.userns.conf.in \
-       $(srcdir)/fedora.common.conf.in \
-       $(srcdir)/fedora.userns.conf.in \
-       $(srcdir)/gentoo.common.conf.in \
-       $(srcdir)/gentoo.moresecure.conf.in \
-       $(srcdir)/gentoo.userns.conf.in $(srcdir)/nesting.conf.in \
-       $(srcdir)/opensuse.common.conf.in \
-       $(srcdir)/opensuse.userns.conf.in \
-       $(srcdir)/oracle.common.conf.in \
-       $(srcdir)/oracle.userns.conf.in $(srcdir)/plamo.common.conf.in \
-       $(srcdir)/plamo.userns.conf.in \
-       $(srcdir)/ubuntu-cloud.common.conf.in \
-       $(srcdir)/ubuntu-cloud.lucid.conf.in \
-       $(srcdir)/ubuntu-cloud.userns.conf.in \
-       $(srcdir)/ubuntu.common.conf.in $(srcdir)/ubuntu.lucid.conf.in \
-       $(srcdir)/ubuntu.userns.conf.in \
-       $(srcdir)/openwrt.common.conf.in $(srcdir)/userns.conf.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
-CONFIG_CLEAN_FILES = archlinux.common.conf archlinux.userns.conf \
-       centos.common.conf centos.userns.conf common.conf \
-       debian.common.conf debian.userns.conf fedora.common.conf \
-       fedora.userns.conf gentoo.common.conf gentoo.moresecure.conf \
-       gentoo.userns.conf nesting.conf opensuse.common.conf \
-       opensuse.userns.conf oracle.common.conf oracle.userns.conf \
-       plamo.common.conf plamo.userns.conf ubuntu-cloud.common.conf \
-       ubuntu-cloud.lucid.conf ubuntu-cloud.userns.conf \
-       ubuntu.common.conf ubuntu.lucid.conf ubuntu.userns.conf \
-       openwrt.common.conf userns.conf
+CONFIG_CLEAN_FILES = alpine.common.conf alpine.userns.conf \
+       archlinux.common.conf archlinux.userns.conf centos.common.conf \
+       centos.userns.conf common.conf debian.common.conf \
+       debian.userns.conf fedora.common.conf fedora.userns.conf \
+       gentoo.common.conf gentoo.moresecure.conf gentoo.userns.conf \
+       nesting.conf opensuse.common.conf opensuse.userns.conf \
+       oracle.common.conf oracle.userns.conf plamo.common.conf \
+       plamo.userns.conf slackware.common.conf slackware.userns.conf \
+       ubuntu-cloud.common.conf ubuntu-cloud.lucid.conf \
+       ubuntu-cloud.userns.conf ubuntu.common.conf ubuntu.lucid.conf \
+       ubuntu.userns.conf openwrt.common.conf sparclinux.common.conf \
+       sparclinux.userns.conf userns.conf
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -204,6 +194,35 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+       $(srcdir)/alpine.common.conf.in \
+       $(srcdir)/alpine.userns.conf.in \
+       $(srcdir)/archlinux.common.conf.in \
+       $(srcdir)/archlinux.userns.conf.in \
+       $(srcdir)/centos.common.conf.in \
+       $(srcdir)/centos.userns.conf.in $(srcdir)/common.conf.in \
+       $(srcdir)/debian.common.conf.in \
+       $(srcdir)/debian.userns.conf.in \
+       $(srcdir)/fedora.common.conf.in \
+       $(srcdir)/fedora.userns.conf.in \
+       $(srcdir)/gentoo.common.conf.in \
+       $(srcdir)/gentoo.moresecure.conf.in \
+       $(srcdir)/gentoo.userns.conf.in $(srcdir)/nesting.conf.in \
+       $(srcdir)/opensuse.common.conf.in \
+       $(srcdir)/opensuse.userns.conf.in \
+       $(srcdir)/openwrt.common.conf.in \
+       $(srcdir)/oracle.common.conf.in \
+       $(srcdir)/oracle.userns.conf.in $(srcdir)/plamo.common.conf.in \
+       $(srcdir)/plamo.userns.conf.in \
+       $(srcdir)/slackware.common.conf.in \
+       $(srcdir)/slackware.userns.conf.in \
+       $(srcdir)/sparclinux.common.conf.in \
+       $(srcdir)/sparclinux.userns.conf.in \
+       $(srcdir)/ubuntu-cloud.common.conf.in \
+       $(srcdir)/ubuntu-cloud.lucid.conf.in \
+       $(srcdir)/ubuntu-cloud.userns.conf.in \
+       $(srcdir)/ubuntu.common.conf.in $(srcdir)/ubuntu.lucid.conf.in \
+       $(srcdir)/ubuntu.userns.conf.in $(srcdir)/userns.conf.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -281,6 +300,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -294,6 +314,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -385,6 +406,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -397,6 +419,8 @@ templatesconfigdir = @LXCTEMPLATECONFIG@
 EXTRA_DIST = common.seccomp
 SUBDIRS = common.conf.d
 templatesconfig_DATA = \
+       alpine.common.conf \
+       alpine.userns.conf \
        archlinux.common.conf \
        archlinux.userns.conf \
        centos.common.conf \
@@ -417,6 +441,8 @@ templatesconfig_DATA = \
        oracle.userns.conf \
        plamo.common.conf \
        plamo.userns.conf \
+       slackware.common.conf \
+       slackware.userns.conf \
        ubuntu-cloud.common.conf \
        ubuntu-cloud.lucid.conf \
        ubuntu-cloud.userns.conf \
@@ -424,6 +450,8 @@ templatesconfig_DATA = \
        ubuntu.lucid.conf \
        ubuntu.userns.conf \
        openwrt.common.conf \
+       sparclinux.common.conf \
+       sparclinux.userns.conf \
        userns.conf
 
 all: all-recursive
@@ -441,7 +469,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/templates/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/templates/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -459,6 +486,10 @@ $(top_srcdir)/configure:  $(am__configure_deps)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
        cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
+alpine.common.conf: $(top_builddir)/config.status $(srcdir)/alpine.common.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+alpine.userns.conf: $(top_builddir)/config.status $(srcdir)/alpine.userns.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 archlinux.common.conf: $(top_builddir)/config.status $(srcdir)/archlinux.common.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 archlinux.userns.conf: $(top_builddir)/config.status $(srcdir)/archlinux.userns.conf.in
@@ -497,6 +528,10 @@ plamo.common.conf: $(top_builddir)/config.status $(srcdir)/plamo.common.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 plamo.userns.conf: $(top_builddir)/config.status $(srcdir)/plamo.userns.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+slackware.common.conf: $(top_builddir)/config.status $(srcdir)/slackware.common.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+slackware.userns.conf: $(top_builddir)/config.status $(srcdir)/slackware.userns.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 ubuntu-cloud.common.conf: $(top_builddir)/config.status $(srcdir)/ubuntu-cloud.common.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 ubuntu-cloud.lucid.conf: $(top_builddir)/config.status $(srcdir)/ubuntu-cloud.lucid.conf.in
@@ -511,6 +546,10 @@ ubuntu.userns.conf: $(top_builddir)/config.status $(srcdir)/ubuntu.userns.conf.i
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 openwrt.common.conf: $(top_builddir)/config.status $(srcdir)/openwrt.common.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sparclinux.common.conf: $(top_builddir)/config.status $(srcdir)/sparclinux.common.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sparclinux.userns.conf: $(top_builddir)/config.status $(srcdir)/sparclinux.userns.conf.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 userns.conf: $(top_builddir)/config.status $(srcdir)/userns.conf.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 install-templatesconfigDATA: $(templatesconfig_DATA)
@@ -809,6 +848,8 @@ uninstall-am: uninstall-templatesconfigDATA
        pdf-am ps ps-am tags tags-am uninstall uninstall-am \
        uninstall-templatesconfigDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/config/templates/alpine.common.conf.in b/config/templates/alpine.common.conf.in
new file mode 100644 (file)
index 0000000..034a33b
--- /dev/null
@@ -0,0 +1,20 @@
+# This derives from the global common config.
+lxc.include = @LXCTEMPLATECONFIG@/common.conf
+
+# Doesn't support consoles in /dev/lxc/.
+lxc.devttydir =
+
+# Drop another (potentially) harmful capabilities.
+lxc.cap.drop = audit_write
+lxc.cap.drop = ipc_owner
+lxc.cap.drop = mknod
+lxc.cap.drop = setfcap
+lxc.cap.drop = setpcap
+lxc.cap.drop = sys_nice
+lxc.cap.drop = sys_pacct
+lxc.cap.drop = sys_ptrace
+lxc.cap.drop = sys_rawio
+lxc.cap.drop = sys_resource
+lxc.cap.drop = sys_tty_config
+lxc.cap.drop = syslog
+lxc.cap.drop = wake_alarm
diff --git a/config/templates/alpine.userns.conf.in b/config/templates/alpine.userns.conf.in
new file mode 100644 (file)
index 0000000..4336b44
--- /dev/null
@@ -0,0 +1,2 @@
+# This derives from the global userns config.
+lxc.include = @LXCTEMPLATECONFIG@/userns.conf
index ccbed68..150bcd0 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/templates/common.conf.d
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -138,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(templatesconfigdir)"
 DATA = $(templatesconfig_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -322,7 +336,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/templates/common.conf.d/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/templates/common.conf.d/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -515,6 +528,8 @@ uninstall-am: uninstall-templatesconfigDATA
        mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
        uninstall uninstall-am uninstall-templatesconfigDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 80f31ce..c1deade 100644 (file)
@@ -10,7 +10,7 @@ lxc.pts = 1024
 lxc.tty = 4
 
 # Drop some harmful capabilities
-lxc.cap.drop = mac_admin mac_override sys_time sys_module
+lxc.cap.drop = mac_admin mac_override sys_time sys_module sys_rawio
 
 # Set the pivot directory
 lxc.pivotdir = lxc_putold
index e034b95..07c2bc8 100644 (file)
@@ -9,10 +9,6 @@ lxc.devttydir =
 # (uncommented) to the container's configuration file.
 #lxc.aa_profile = unconfined
 
-# To support container nesting on an Ubuntu host while retaining most of
-# apparmor's added security, use the following line instead.
-#lxc.aa_profile = lxc-container-default-with-nesting
-
 # If you wish to allow mounting block filesystems, then use the following
 # line instead, and make sure to grant access to the block device and/or loop
 # devices below in lxc.cgroup.devices.allow.
diff --git a/config/templates/slackware.common.conf.in b/config/templates/slackware.common.conf.in
new file mode 100644 (file)
index 0000000..191099f
--- /dev/null
@@ -0,0 +1,46 @@
+# This derives from the global common config
+lxc.include = @LXCTEMPLATECONFIG@/common.conf
+
+# Doesn't support consoles in /dev/lxc/
+lxc.devttydir =
+
+# Extra cgroup device access
+## rtc
+lxc.cgroup.devices.allow = c 254:0 rm
+## tun
+lxc.cgroup.devices.allow = c 10:200 rwm
+## hpet
+lxc.cgroup.devices.allow = c 10:228 rwm
+## kvm
+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
+
+# mount /dev/shm as tmpfs
+lxc.mount.entry = none dev/shm tmpfs rw,nosuid,nodev,create=dir
+
+# Capabilities
+# Uncomment these if you don't run anything that needs the capability, and
+# would like the container to run with less privilege.
+# Note that some are already dropped in common.conf.
+#
+# Dropping sys_admin disables container root from doing a lot of things
+# that could be bad like re-mounting lxc fstab entries rw for example,
+# but also disables some useful things like being able to nfs mount, and
+# things that are already namespaced with ns_capable() kernel checks, like
+# hostname(1).
+#
+# Some of these don't apply in Slackware but are here for future reference.
+#
+# lxc.cap.drop = sys_admin        # breaks systemd
+# lxc.cap.drop = net_raw          # breaks dhcp/ping
+# lxc.cap.drop = setgid           # breaks login (initgroups/setgroups)
+# lxc.cap.drop = dac_read_search  # breaks login (pam unix_chkpwd)
+# lxc.cap.drop = setuid           # breaks sshd,nfs statd
+# lxc.cap.drop = audit_control    # breaks sshd (set_loginuid failed)
+# lxc.cap.drop = audit_write
+# lxc.cap.drop = setpcap          # breaks journald
+# lxc.cap.drop = sys_resources    # breaks systemd
+#
+lxc.cap.drop = mknod setfcap setpcap
diff --git a/config/templates/slackware.userns.conf.in b/config/templates/slackware.userns.conf.in
new file mode 100644 (file)
index 0000000..707bb30
--- /dev/null
@@ -0,0 +1,2 @@
+# This derives from the global userns config
+lxc.include = @LXCTEMPLATECONFIG@/userns.conf
diff --git a/config/templates/sparclinux.common.conf.in b/config/templates/sparclinux.common.conf.in
new file mode 100644 (file)
index 0000000..8a72ad0
--- /dev/null
@@ -0,0 +1,20 @@
+# This derives from the global common config
+lxc.include = @LXCTEMPLATECONFIG@/common.conf
+
+# Capabilities
+# Uncomment these if you don't run anything that needs the capability, and
+# would like the container to run with less privilege.
+#
+# Dropping sys_admin disables container root from doing a lot of things
+# that could be bad like re-mounting lxc fstab entries rw for example,
+# but also disables some useful things like being able to nfs mount, and
+# things that are already namespaced with ns_capable() kernel checks, like
+# hostname(1).
+# lxc.cap.drop = sys_admin
+# lxc.cap.drop = net_raw          # breaks dhcp/ping
+# lxc.cap.drop = setgid           # breaks login (initgroups/setgroups)
+# lxc.cap.drop = dac_read_search  # breaks login (pam unix_chkpwd)
+# lxc.cap.drop = setuid           # breaks sshd,nfs statd
+# lxc.cap.drop = audit_control    # breaks sshd (set_loginuid failed)
+# lxc.cap.drop = audit_write
+lxc.cap.drop = sys_nice sys_pacct sys_rawio
diff --git a/config/templates/sparclinux.userns.conf.in b/config/templates/sparclinux.userns.conf.in
new file mode 100644 (file)
index 0000000..707bb30
--- /dev/null
@@ -0,0 +1,2 @@
+# This derives from the global userns config
+lxc.include = @LXCTEMPLATECONFIG@/userns.conf
index 7e171de..a1c60d2 100644 (file)
@@ -12,10 +12,6 @@ lxc.mount.entry = mqueue dev/mqueue mqueue rw,relatime,create=dir,optional 0 0
 # (uncommented) to the container's configuration file.
 #lxc.aa_profile = unconfined
 
-# To support container nesting on an Ubuntu host while retaining most of
-# apparmor's added security, use the following line instead.
-#lxc.aa_profile = lxc-container-default-with-nesting
-
 # Uncomment the following line to autodetect squid-deb-proxy configuration on the
 # host and forward it to the guest at start time.
 #lxc.hook.pre-start = /usr/share/lxc/hooks/squid-deb-proxy-client
index 4f8431d..98ec55a 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = config/yum
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -138,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(yumpluginsdir)"
 DATA = $(yumplugins_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -322,7 +336,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu config/yum/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu config/yum/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -515,6 +528,8 @@ uninstall-am: uninstall-yumpluginsDATA
        pdf-am ps ps-am tags-am uninstall uninstall-am \
        uninstall-yumpluginsDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 1a31023..51c7c6e 100755 (executable)
--- 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.5.
+# Generated by GNU Autoconf 2.69 for lxc 2.0.0.
 #
 #
 # 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.5'
-PACKAGE_STRING='lxc 1.1.5'
+PACKAGE_VERSION='2.0.0'
+PACKAGE_STRING='lxc 2.0.0'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -626,6 +626,8 @@ LIBOBJS
 SED
 HAVE_FGETLN_FALSE
 HAVE_FGETLN_TRUE
+HAVE_GETSUBOPT_FALSE
+HAVE_GETSUBOPT_TRUE
 HAVE_GETLINE_FALSE
 HAVE_GETLINE_TRUE
 IS_BIONIC_FALSE
@@ -634,6 +636,7 @@ DEFAULT_CGROUP_PATTERN
 RUNTIME_PATH
 LOGPATH
 LXCINITDIR
+LXCBINHOOKDIR
 LXCHOOKDIR
 LXCTEMPLATECONFIG
 LXCTEMPLATEDIR
@@ -721,6 +724,8 @@ ENABLE_DOCBOOK_TRUE
 db2xman
 ENABLE_RPATH_FALSE
 ENABLE_RPATH_TRUE
+ENABLE_DEPRECATED_FALSE
+ENABLE_DEPRECATED_TRUE
 SYSTEMD_UNIT_DIR
 INIT_SCRIPT_UPSTART_FALSE
 INIT_SCRIPT_UPSTART_TRUE
@@ -788,6 +793,7 @@ INSTALL_DATA
 INSTALL_SCRIPT
 INSTALL_PROGRAM
 LXC_VERSION
+LXC_VERSION_ABI
 LXC_VERSION_MICRO
 LXC_VERSION_MINOR
 LXC_VERSION_MAJOR
@@ -815,6 +821,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -842,6 +849,7 @@ enable_dependency_tracking
 with_distro
 with_init_script
 with_systemdsystemunitdir
+enable_deprecated
 enable_rpath
 enable_doc
 enable_api_docs
@@ -933,6 +941,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1185,6 +1194,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1322,7 +1340,7 @@ fi
 for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir
+               libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1435,7 +1453,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.5 to adapt to many kinds of systems.
+\`configure' configures lxc 2.0.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1475,6 +1493,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1505,7 +1524,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of lxc 1.1.5:";;
+     short | recursive ) echo "Configuration of lxc 2.0.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1519,6 +1538,7 @@ Optional Features:
                           do not reject slow dependency extractors
   --disable-dependency-tracking
                           speeds up one-time build
+  --enable-deprecated     enable deprecated executables [default=no]
   --enable-rpath          set rpath in executables [default=no]
   --enable-doc            make man pages [default=auto]
   --enable-api-docs       make API documentation [default=auto]
@@ -1542,8 +1562,8 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-distro=DISTRO    Specify the Linux distribution to target: One of
                           redhat, oracle, centos, fedora, suse, gentoo,
-                          debian, arch, slackware, paldo, openmandriva or
-                          pardus.
+                          debian, arch, slackware, plamo, paldo, openmandriva,
+                          pardus, sparclinux, altlinux.
   --with-init-script[=TYPE[,TYPE,...]]
                           Type(s) of init script to install: sysvinit,
                           systemd, upstart, distro [default=distro]
@@ -1665,7 +1685,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-lxc configure 1.1.5
+lxc configure 2.0.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2130,7 +2150,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.5, which was
+It was created by lxc $as_me 2.0.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2601,17 +2621,19 @@ $as_echo "no" >&6; }
        fi
 fi
 
-LXC_VERSION_BASE=1.1.5
+LXC_VERSION_BASE=2.0.0
+
 
 
+LXC_VERSION_MAJOR=2
 
-LXC_VERSION_MAJOR=1
+LXC_VERSION_MINOR=0
 
-LXC_VERSION_MINOR=1
+LXC_VERSION_MICRO=0
 
-LXC_VERSION_MICRO=5
+LXC_VERSION_ABI=1.2.0
 
-LXC_VERSION=1.1.5
+LXC_VERSION=2.0.0
 
 
 
@@ -2646,7 +2668,7 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 ac_config_headers="$ac_config_headers src/config.h"
 
-am__api_version='1.14'
+am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -2818,8 +2840,8 @@ test "$program_suffix" != NONE &&
 ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
 program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
 
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
   case $am_aux_dir in
@@ -2838,7 +2860,7 @@ else
 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\    *)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -3132,7 +3154,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='lxc'
- VERSION='1.1.5'
+ VERSION='2.0.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3166,8 +3188,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 mkdir_p='$(MKDIR_P)'
 
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 # Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
@@ -3224,6 +3246,7 @@ END
     as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
   fi
 fi
+
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
   as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
@@ -4848,6 +4871,25 @@ if test "x$ac_cv_file__etc_oracle_release" = xyes; then :
   with_distro="oracle"
 fi
 
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/sparclinux-release" >&5
+$as_echo_n "checking for /etc/sparclinux-release... " >&6; }
+if ${ac_cv_file__etc_sparclinux_release+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/etc/sparclinux-release"; then
+  ac_cv_file__etc_sparclinux_release=yes
+else
+  ac_cv_file__etc_sparclinux_release=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_sparclinux_release" >&5
+$as_echo "$ac_cv_file__etc_sparclinux_release" >&6; }
+if test "x$ac_cv_file__etc_sparclinux_release" = xyes; then :
+  with_distro="sparclinux"
+fi
+
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/centos-release" >&5
 $as_echo_n "checking for /etc/centos-release... " >&6; }
 if ${ac_cv_file__etc_centos_release+:} false; then :
@@ -4981,6 +5023,25 @@ if test "x$ac_cv_file__etc_slackware_version" = xyes; then :
   with_distro="slackware"
 fi
 
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/plamo-version" >&5
+$as_echo_n "checking for /etc/plamo-version... " >&6; }
+if ${ac_cv_file__etc_plamo_version+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/etc/plamo-version"; then
+  ac_cv_file__etc_plamo_version=yes
+else
+  ac_cv_file__etc_plamo_version=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_plamo_version" >&5
+$as_echo "$ac_cv_file__etc_plamo_version" >&6; }
+if test "x$ac_cv_file__etc_plamo_version" = xyes; then :
+  with_distro="plamo"
+fi
+
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/frugalware-release" >&5
 $as_echo_n "checking for /etc/frugalware-release... " >&6; }
 if ${ac_cv_file__etc_frugalware_release+:} false; then :
@@ -5057,9 +5118,32 @@ if test "x$ac_cv_file__etc_pardus_release" = xyes; then :
   with_distro="pardus"
 fi
 
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/altlinux-release" >&5
+$as_echo_n "checking for /etc/altlinux-release... " >&6; }
+if ${ac_cv_file__etc_altlinux_release+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/etc/altlinux-release"; then
+  ac_cv_file__etc_altlinux_release=yes
+else
+  ac_cv_file__etc_altlinux_release=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_altlinux_release" >&5
+$as_echo "$ac_cv_file__etc_altlinux_release" >&6; }
+if test "x$ac_cv_file__etc_altlinux_release" = xyes; then :
+  with_distro="altlinux"
+fi
+
 fi
 with_distro=`echo ${with_distro} | tr '[:upper:]' '[:lower:]'`
 
+if test "z$with_distro" = "zforsparc"; then
+       with_distro="sparclinux"
+fi
+
 if test "z$with_distro" = "z"; then
        with_distro="unknown"
 fi
@@ -5068,7 +5152,7 @@ case $with_distro in
                distroconf=default.conf.lxcbr
                distrosysconf="$sysconfdir/default"
                ;;
-       redhat|centos|fedora|oracle|oracleserver|suse|opensuse*)
+       redhat|centos|fedora|oracle|oracleserver|sparclinux|altlinux|suse|opensuse*|plamo)
                distroconf=default.conf.lxcbr
                distrosysconf="$sysconfdir/sysconfig"
                ;;
@@ -5113,10 +5197,10 @@ fi
 case "$with_init_script" in
        distro)
                case $with_distro in
-                       fedora|opensuse*)
+                       fedora|altlinux|opensuse*)
                                init_script=systemd
                                ;;
-                       redhat|centos|oracle|oracleserver)
+                       redhat|centos|oracle|oracleserver|sparclinux|plamo)
                                init_script=sysvinit
                                ;;
                        debian|raspbian)
@@ -5192,6 +5276,23 @@ if test "x$with_systemdsystemunitdir" != "xno"; then
 
 fi
 
+# Allow enabling deprecated executables
+# Check whether --enable-deprecated was given.
+if test "${enable_deprecated+set}" = set; then :
+  enableval=$enable_deprecated;
+else
+  enable_deprecated=false
+fi
+
+ if test "x$enable_deprecated" = "xyes"; then
+  ENABLE_DEPRECATED_TRUE=
+  ENABLE_DEPRECATED_FALSE='#'
+else
+  ENABLE_DEPRECATED_TRUE='#'
+  ENABLE_DEPRECATED_FALSE=
+fi
+
+
 # Allow disabling rpath
 # Check whether --enable-rpath was given.
 if test "${enable_rpath+set}" = set; then :
@@ -7140,7 +7241,6 @@ fi
 # shell variable SOURCE.
 
 
-# PKG_CHECK_VAR
 
 
 # Lua module and scripts
@@ -7884,7 +7984,8 @@ fi
 if test -z "$ENABLE_LUA_TRUE"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking Lua version" >&5
 $as_echo_n "checking Lua version... " >&6; }
-                 if test -n "$LUA_VERSION"; then
+
+if test -n "$LUA_VERSION"; then
     pkg_cv_LUA_VERSION="$LUA_VERSION"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
@@ -7901,9 +8002,11 @@ fi
  else
     pkg_failed=untried
 fi
-     LUA_VERSION=$pkg_cv_LUA_VERSION
-     if test "x$LUA_VERSION" = x""; then :
-            if test -n "$LUA_VERSION"; then
+LUA_VERSION=$pkg_cv_LUA_VERSION
+
+if test "x$LUA_VERSION" = x""; then :
+
+if test -n "$LUA_VERSION"; then
     pkg_cv_LUA_VERSION="$LUA_VERSION"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
@@ -7920,8 +8023,9 @@ fi
  else
     pkg_failed=untried
 fi
-     LUA_VERSION=$pkg_cv_LUA_VERSION
-     if test "x$LUA_VERSION" = x""; then :
+LUA_VERSION=$pkg_cv_LUA_VERSION
+
+if test "x$LUA_VERSION" = x""; then :
 
 fi
 fi
@@ -8666,6 +8770,34 @@ fi
     exec_prefix=$exec_prefix_save
 
 
+    EXP_VAR=LXCBINHOOKDIR
+    FROM_VAR="$libexecdir/lxc/hooks"
+
+        prefix_save=$prefix
+    exec_prefix_save=$exec_prefix
+
+        if test "x$prefix" = "xNONE"; then
+        prefix="$ac_default_prefix"
+    fi
+        if test "x$exec_prefix" = "xNONE"; then
+        exec_prefix=$prefix
+    fi
+
+    full_var="$FROM_VAR"
+        while true; do
+        new_full_var="`eval echo $full_var`"
+        if test "x$new_full_var" = "x$full_var"; then break; fi
+        full_var=$new_full_var
+    done
+
+        full_var=$new_full_var
+    LXCBINHOOKDIR="$full_var"
+
+
+        prefix=$prefix_save
+    exec_prefix=$exec_prefix_save
+
+
     EXP_VAR=LXCINITDIR
     FROM_VAR="$libexecdir"
 
@@ -9010,6 +9142,36 @@ fi
 fi
 done
 
+for ac_func in getsubopt
+do :
+  ac_fn_c_check_func "$LINENO" "getsubopt" "ac_cv_func_getsubopt"
+if test "x$ac_cv_func_getsubopt" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETSUBOPT 1
+_ACEOF
+  if true; then
+  HAVE_GETSUBOPT_TRUE=
+  HAVE_GETSUBOPT_FALSE='#'
+else
+  HAVE_GETSUBOPT_TRUE='#'
+  HAVE_GETSUBOPT_FALSE=
+fi
+
+
+$as_echo "#define HAVE_GETSUBOPT 1" >>confdefs.h
+
+else
+   if false; then
+  HAVE_GETSUBOPT_TRUE=
+  HAVE_GETSUBOPT_FALSE='#'
+else
+  HAVE_GETSUBOPT_TRUE='#'
+  HAVE_GETSUBOPT_FALSE=
+fi
+
+fi
+done
+
 for ac_func in fgetln
 do :
   ac_fn_c_check_func "$LINENO" "fgetln" "ac_cv_func_fgetln"
@@ -9305,7 +9467,7 @@ if test "x$GCC" = "xyes"; then
 fi
 
 # Files requiring some variable expansion
-ac_config_files="$ac_config_files Makefile lxc.pc lxc.spec config/Makefile config/apparmor/Makefile config/selinux/Makefile config/bash/Makefile config/bash/lxc config/init/Makefile config/init/common/Makefile config/init/common/lxc-containers config/init/common/lxc-net config/init/systemd/Makefile config/init/systemd/lxc.service config/init/systemd/lxc-net.service config/init/sysvinit/Makefile config/init/sysvinit/lxc-containers config/init/sysvinit/lxc-net config/init/upstart/lxc-net.conf config/init/upstart/Makefile config/etc/Makefile config/templates/Makefile config/templates/archlinux.common.conf config/templates/archlinux.userns.conf config/templates/centos.common.conf config/templates/centos.userns.conf config/templates/common.conf config/templates/common.conf.d/Makefile config/templates/debian.common.conf config/templates/debian.userns.conf config/templates/fedora.common.conf config/templates/fedora.userns.conf config/templates/gentoo.common.conf config/templates/gentoo.moresecure.conf config/templates/gentoo.userns.conf config/templates/nesting.conf config/templates/opensuse.common.conf config/templates/opensuse.userns.conf config/templates/oracle.common.conf config/templates/oracle.userns.conf config/templates/plamo.common.conf config/templates/plamo.userns.conf config/templates/ubuntu-cloud.common.conf config/templates/ubuntu-cloud.lucid.conf config/templates/ubuntu-cloud.userns.conf config/templates/ubuntu.common.conf config/templates/ubuntu.lucid.conf config/templates/ubuntu.userns.conf config/templates/openwrt.common.conf config/templates/userns.conf config/yum/Makefile config/sysconfig/Makefile config/sysconfig/lxc doc/Makefile doc/api/Makefile doc/legacy/lxc-ls.sgml doc/lxc-attach.sgml doc/lxc-autostart.sgml doc/lxc-cgroup.sgml doc/lxc-checkconfig.sgml doc/lxc-checkpoint.sgml doc/lxc-clone.sgml doc/lxc-config.sgml doc/lxc-console.sgml doc/lxc-create.sgml doc/lxc-destroy.sgml doc/lxc-device.sgml doc/lxc-execute.sgml doc/lxc-freeze.sgml doc/lxc-info.sgml doc/lxc-ls.sgml doc/lxc-monitor.sgml doc/lxc-snapshot.sgml doc/lxc-start-ephemeral.sgml doc/lxc-start.sgml doc/lxc-stop.sgml doc/lxc-top.sgml doc/lxc-unfreeze.sgml doc/lxc-unshare.sgml doc/lxc-user-nic.sgml doc/lxc-usernsexec.sgml doc/lxc-wait.sgml doc/lxc.conf.sgml doc/lxc.container.conf.sgml doc/lxc.system.conf.sgml doc/lxc-usernet.sgml doc/lxc.sgml doc/common_options.sgml doc/see_also.sgml doc/rootfs/Makefile doc/examples/Makefile doc/examples/lxc-macvlan.conf doc/examples/lxc-vlan.conf doc/examples/lxc-no-netns.conf doc/examples/lxc-empty-netns.conf doc/examples/lxc-phys.conf doc/examples/lxc-veth.conf doc/examples/lxc-complex.conf doc/ja/Makefile doc/ja/legacy/lxc-ls.sgml doc/ja/lxc-attach.sgml doc/ja/lxc-autostart.sgml doc/ja/lxc-cgroup.sgml doc/ja/lxc-checkconfig.sgml doc/ja/lxc-checkpoint.sgml doc/ja/lxc-clone.sgml doc/ja/lxc-config.sgml doc/ja/lxc-console.sgml doc/ja/lxc-create.sgml doc/ja/lxc-destroy.sgml doc/ja/lxc-device.sgml doc/ja/lxc-execute.sgml doc/ja/lxc-freeze.sgml doc/ja/lxc-info.sgml doc/ja/lxc-ls.sgml doc/ja/lxc-monitor.sgml doc/ja/lxc-snapshot.sgml doc/ja/lxc-start-ephemeral.sgml doc/ja/lxc-start.sgml doc/ja/lxc-stop.sgml doc/ja/lxc-top.sgml doc/ja/lxc-unfreeze.sgml doc/ja/lxc-unshare.sgml doc/ja/lxc-user-nic.sgml doc/ja/lxc-usernsexec.sgml doc/ja/lxc-wait.sgml doc/ja/lxc.conf.sgml doc/ja/lxc.container.conf.sgml doc/ja/lxc.system.conf.sgml doc/ja/lxc-usernet.sgml doc/ja/lxc.sgml doc/ja/common_options.sgml doc/ja/see_also.sgml hooks/Makefile templates/Makefile templates/lxc-alpine templates/lxc-altlinux templates/lxc-archlinux templates/lxc-busybox templates/lxc-centos templates/lxc-cirros templates/lxc-debian templates/lxc-download templates/lxc-fedora templates/lxc-gentoo templates/lxc-openmandriva templates/lxc-opensuse templates/lxc-oracle templates/lxc-plamo templates/lxc-sshd templates/lxc-ubuntu templates/lxc-ubuntu-cloud src/Makefile src/lxc/Makefile src/lxc/lxc-checkconfig src/lxc/lxc-ls src/lxc/lxc-start-ephemeral src/lxc/legacy/lxc-ls src/lxc/lxc.functions src/lxc/version.h src/python-lxc/Makefile src/python-lxc/setup.py src/lua-lxc/Makefile src/tests/Makefile src/tests/lxc-test-usernic"
+ac_config_files="$ac_config_files Makefile lxc.pc lxc.spec config/Makefile config/apparmor/Makefile config/selinux/Makefile config/bash/Makefile config/bash/lxc config/init/Makefile config/init/common/Makefile config/init/common/lxc-containers config/init/common/lxc-net config/init/systemd/Makefile config/init/systemd/lxc.service config/init/systemd/lxc@.service config/init/systemd/lxc-net.service config/init/sysvinit/Makefile config/init/sysvinit/lxc-containers config/init/sysvinit/lxc-net config/init/upstart/lxc.conf config/init/upstart/lxc-net.conf config/init/upstart/Makefile config/etc/Makefile config/templates/Makefile config/templates/alpine.common.conf config/templates/alpine.userns.conf config/templates/archlinux.common.conf config/templates/archlinux.userns.conf config/templates/centos.common.conf config/templates/centos.userns.conf config/templates/common.conf config/templates/common.conf.d/Makefile config/templates/debian.common.conf config/templates/debian.userns.conf config/templates/fedora.common.conf config/templates/fedora.userns.conf config/templates/gentoo.common.conf config/templates/gentoo.moresecure.conf config/templates/gentoo.userns.conf config/templates/nesting.conf config/templates/opensuse.common.conf config/templates/opensuse.userns.conf config/templates/oracle.common.conf config/templates/oracle.userns.conf config/templates/plamo.common.conf config/templates/plamo.userns.conf config/templates/slackware.common.conf config/templates/slackware.userns.conf config/templates/ubuntu-cloud.common.conf config/templates/ubuntu-cloud.lucid.conf config/templates/ubuntu-cloud.userns.conf config/templates/ubuntu.common.conf config/templates/ubuntu.lucid.conf config/templates/ubuntu.userns.conf config/templates/openwrt.common.conf config/templates/sparclinux.common.conf config/templates/sparclinux.userns.conf config/templates/userns.conf config/yum/Makefile config/sysconfig/Makefile config/sysconfig/lxc doc/Makefile doc/api/Makefile doc/lxc-attach.sgml doc/lxc-autostart.sgml doc/lxc-cgroup.sgml doc/lxc-checkconfig.sgml doc/lxc-checkpoint.sgml doc/lxc-clone.sgml doc/lxc-config.sgml doc/lxc-console.sgml doc/lxc-copy.sgml doc/lxc-create.sgml doc/lxc-destroy.sgml doc/lxc-device.sgml doc/lxc-execute.sgml doc/lxc-freeze.sgml doc/lxc-info.sgml doc/lxc-ls.sgml doc/lxc-monitor.sgml doc/lxc-snapshot.sgml doc/lxc-start-ephemeral.sgml doc/lxc-start.sgml doc/lxc-stop.sgml doc/lxc-top.sgml doc/lxc-unfreeze.sgml doc/lxc-unshare.sgml doc/lxc-user-nic.sgml doc/lxc-usernsexec.sgml doc/lxc-wait.sgml doc/lxc.conf.sgml doc/lxc.container.conf.sgml doc/lxc.system.conf.sgml doc/lxc-usernet.sgml doc/lxc.sgml doc/common_options.sgml doc/see_also.sgml doc/rootfs/Makefile doc/examples/Makefile doc/examples/lxc-macvlan.conf doc/examples/lxc-vlan.conf doc/examples/lxc-no-netns.conf doc/examples/lxc-empty-netns.conf doc/examples/lxc-phys.conf doc/examples/lxc-veth.conf doc/examples/lxc-complex.conf doc/ja/Makefile doc/ja/lxc-attach.sgml doc/ja/lxc-autostart.sgml doc/ja/lxc-cgroup.sgml doc/ja/lxc-checkconfig.sgml doc/ja/lxc-checkpoint.sgml doc/ja/lxc-clone.sgml doc/ja/lxc-config.sgml doc/ja/lxc-console.sgml doc/ja/lxc-copy.sgml doc/ja/lxc-create.sgml doc/ja/lxc-destroy.sgml doc/ja/lxc-device.sgml doc/ja/lxc-execute.sgml doc/ja/lxc-freeze.sgml doc/ja/lxc-info.sgml doc/ja/lxc-ls.sgml doc/ja/lxc-monitor.sgml doc/ja/lxc-snapshot.sgml doc/ja/lxc-start-ephemeral.sgml doc/ja/lxc-start.sgml doc/ja/lxc-stop.sgml doc/ja/lxc-top.sgml doc/ja/lxc-unfreeze.sgml doc/ja/lxc-unshare.sgml doc/ja/lxc-user-nic.sgml doc/ja/lxc-usernsexec.sgml doc/ja/lxc-wait.sgml doc/ja/lxc.conf.sgml doc/ja/lxc.container.conf.sgml doc/ja/lxc.system.conf.sgml doc/ja/lxc-usernet.sgml doc/ja/lxc.sgml doc/ja/common_options.sgml doc/ja/see_also.sgml doc/ko/Makefile doc/ko/lxc-attach.sgml doc/ko/lxc-autostart.sgml doc/ko/lxc-cgroup.sgml doc/ko/lxc-checkconfig.sgml doc/ko/lxc-checkpoint.sgml doc/ko/lxc-clone.sgml doc/ko/lxc-config.sgml doc/ko/lxc-console.sgml doc/ko/lxc-copy.sgml doc/ko/lxc-create.sgml doc/ko/lxc-destroy.sgml doc/ko/lxc-device.sgml doc/ko/lxc-execute.sgml doc/ko/lxc-freeze.sgml doc/ko/lxc-info.sgml doc/ko/lxc-ls.sgml doc/ko/lxc-monitor.sgml doc/ko/lxc-snapshot.sgml doc/ko/lxc-start-ephemeral.sgml doc/ko/lxc-start.sgml doc/ko/lxc-stop.sgml doc/ko/lxc-top.sgml doc/ko/lxc-unfreeze.sgml doc/ko/lxc-unshare.sgml doc/ko/lxc-user-nic.sgml doc/ko/lxc-usernsexec.sgml doc/ko/lxc-wait.sgml doc/ko/lxc.conf.sgml doc/ko/lxc.container.conf.sgml doc/ko/lxc.system.conf.sgml doc/ko/lxc-usernet.sgml doc/ko/lxc.sgml doc/ko/common_options.sgml doc/ko/see_also.sgml hooks/Makefile templates/Makefile templates/lxc-alpine templates/lxc-altlinux templates/lxc-archlinux templates/lxc-busybox templates/lxc-centos templates/lxc-cirros templates/lxc-debian templates/lxc-download templates/lxc-fedora templates/lxc-gentoo templates/lxc-openmandriva templates/lxc-opensuse templates/lxc-oracle templates/lxc-plamo templates/lxc-slackware templates/lxc-sshd templates/lxc-ubuntu templates/lxc-ubuntu-cloud templates/lxc-sparclinux src/Makefile src/lxc/Makefile src/lxc/lxc-checkconfig src/lxc/lxc-start-ephemeral src/lxc/lxc.functions src/lxc/version.h src/python-lxc/Makefile src/python-lxc/setup.py src/lua-lxc/Makefile src/tests/Makefile src/tests/lxc-test-usernic"
 
 ac_config_commands="$ac_config_commands default"
 
@@ -9462,6 +9624,10 @@ if test -z "${INIT_SCRIPT_UPSTART_TRUE}" && test -z "${INIT_SCRIPT_UPSTART_FALSE
   as_fn_error $? "conditional \"INIT_SCRIPT_UPSTART\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${ENABLE_DEPRECATED_TRUE}" && test -z "${ENABLE_DEPRECATED_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_DEPRECATED\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${ENABLE_RPATH_TRUE}" && test -z "${ENABLE_RPATH_FALSE}"; then
   as_fn_error $? "conditional \"ENABLE_RPATH\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -9542,6 +9708,14 @@ if test -z "${HAVE_GETLINE_TRUE}" && test -z "${HAVE_GETLINE_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_GETLINE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_GETSUBOPT_TRUE}" && test -z "${HAVE_GETSUBOPT_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_GETSUBOPT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_GETSUBOPT_TRUE}" && test -z "${HAVE_GETSUBOPT_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_GETSUBOPT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${HAVE_FGETLN_TRUE}" && test -z "${HAVE_FGETLN_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_FGETLN\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -9947,7 +10121,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.5, which was
+This file was extended by lxc $as_me 2.0.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -10017,7 +10191,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.5
+lxc config.status 2.0.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
     "config/init/common/lxc-net") CONFIG_FILES="$CONFIG_FILES config/init/common/lxc-net" ;;
     "config/init/systemd/Makefile") CONFIG_FILES="$CONFIG_FILES config/init/systemd/Makefile" ;;
     "config/init/systemd/lxc.service") CONFIG_FILES="$CONFIG_FILES config/init/systemd/lxc.service" ;;
+    "config/init/systemd/lxc@.service") CONFIG_FILES="$CONFIG_FILES config/init/systemd/lxc@.service" ;;
     "config/init/systemd/lxc-net.service") CONFIG_FILES="$CONFIG_FILES config/init/systemd/lxc-net.service" ;;
     "config/init/sysvinit/Makefile") CONFIG_FILES="$CONFIG_FILES config/init/sysvinit/Makefile" ;;
     "config/init/sysvinit/lxc-containers") CONFIG_FILES="$CONFIG_FILES config/init/sysvinit/lxc-containers" ;;
     "config/init/sysvinit/lxc-net") CONFIG_FILES="$CONFIG_FILES config/init/sysvinit/lxc-net" ;;
+    "config/init/upstart/lxc.conf") CONFIG_FILES="$CONFIG_FILES config/init/upstart/lxc.conf" ;;
     "config/init/upstart/lxc-net.conf") CONFIG_FILES="$CONFIG_FILES config/init/upstart/lxc-net.conf" ;;
     "config/init/upstart/Makefile") CONFIG_FILES="$CONFIG_FILES config/init/upstart/Makefile" ;;
     "config/etc/Makefile") CONFIG_FILES="$CONFIG_FILES config/etc/Makefile" ;;
     "config/templates/Makefile") CONFIG_FILES="$CONFIG_FILES config/templates/Makefile" ;;
+    "config/templates/alpine.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/alpine.common.conf" ;;
+    "config/templates/alpine.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/alpine.userns.conf" ;;
     "config/templates/archlinux.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/archlinux.common.conf" ;;
     "config/templates/archlinux.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/archlinux.userns.conf" ;;
     "config/templates/centos.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/centos.common.conf" ;;
@@ -10192,6 +10370,8 @@ do
     "config/templates/oracle.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/oracle.userns.conf" ;;
     "config/templates/plamo.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/plamo.common.conf" ;;
     "config/templates/plamo.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/plamo.userns.conf" ;;
+    "config/templates/slackware.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/slackware.common.conf" ;;
+    "config/templates/slackware.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/slackware.userns.conf" ;;
     "config/templates/ubuntu-cloud.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/ubuntu-cloud.common.conf" ;;
     "config/templates/ubuntu-cloud.lucid.conf") CONFIG_FILES="$CONFIG_FILES config/templates/ubuntu-cloud.lucid.conf" ;;
     "config/templates/ubuntu-cloud.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/ubuntu-cloud.userns.conf" ;;
     "config/templates/ubuntu.lucid.conf") CONFIG_FILES="$CONFIG_FILES config/templates/ubuntu.lucid.conf" ;;
     "config/templates/ubuntu.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/ubuntu.userns.conf" ;;
     "config/templates/openwrt.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/openwrt.common.conf" ;;
+    "config/templates/sparclinux.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/sparclinux.common.conf" ;;
+    "config/templates/sparclinux.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/sparclinux.userns.conf" ;;
     "config/templates/userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/userns.conf" ;;
     "config/yum/Makefile") CONFIG_FILES="$CONFIG_FILES config/yum/Makefile" ;;
     "config/sysconfig/Makefile") CONFIG_FILES="$CONFIG_FILES config/sysconfig/Makefile" ;;
     "config/sysconfig/lxc") CONFIG_FILES="$CONFIG_FILES config/sysconfig/lxc" ;;
     "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
     "doc/api/Makefile") CONFIG_FILES="$CONFIG_FILES doc/api/Makefile" ;;
-    "doc/legacy/lxc-ls.sgml") CONFIG_FILES="$CONFIG_FILES doc/legacy/lxc-ls.sgml" ;;
     "doc/lxc-attach.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-attach.sgml" ;;
     "doc/lxc-autostart.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-autostart.sgml" ;;
     "doc/lxc-cgroup.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-cgroup.sgml" ;;
@@ -10214,6 +10395,7 @@ do
     "doc/lxc-clone.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-clone.sgml" ;;
     "doc/lxc-config.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-config.sgml" ;;
     "doc/lxc-console.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-console.sgml" ;;
+    "doc/lxc-copy.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-copy.sgml" ;;
     "doc/lxc-create.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-create.sgml" ;;
     "doc/lxc-destroy.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-destroy.sgml" ;;
     "doc/lxc-device.sgml") CONFIG_FILES="$CONFIG_FILES doc/lxc-device.sgml" ;;
@@ -10249,7 +10431,6 @@ do
     "doc/examples/lxc-veth.conf") CONFIG_FILES="$CONFIG_FILES doc/examples/lxc-veth.conf" ;;
     "doc/examples/lxc-complex.conf") CONFIG_FILES="$CONFIG_FILES doc/examples/lxc-complex.conf" ;;
     "doc/ja/Makefile") CONFIG_FILES="$CONFIG_FILES doc/ja/Makefile" ;;
-    "doc/ja/legacy/lxc-ls.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/legacy/lxc-ls.sgml" ;;
     "doc/ja/lxc-attach.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-attach.sgml" ;;
     "doc/ja/lxc-autostart.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-autostart.sgml" ;;
     "doc/ja/lxc-cgroup.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-cgroup.sgml" ;;
@@ -10258,6 +10439,7 @@ do
     "doc/ja/lxc-clone.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-clone.sgml" ;;
     "doc/ja/lxc-config.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-config.sgml" ;;
     "doc/ja/lxc-console.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-console.sgml" ;;
+    "doc/ja/lxc-copy.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-copy.sgml" ;;
     "doc/ja/lxc-create.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-create.sgml" ;;
     "doc/ja/lxc-destroy.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-destroy.sgml" ;;
     "doc/ja/lxc-device.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc-device.sgml" ;;
     "doc/ja/lxc.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/lxc.sgml" ;;
     "doc/ja/common_options.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/common_options.sgml" ;;
     "doc/ja/see_also.sgml") CONFIG_FILES="$CONFIG_FILES doc/ja/see_also.sgml" ;;
+    "doc/ko/Makefile") CONFIG_FILES="$CONFIG_FILES doc/ko/Makefile" ;;
+    "doc/ko/lxc-attach.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-attach.sgml" ;;
+    "doc/ko/lxc-autostart.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-autostart.sgml" ;;
+    "doc/ko/lxc-cgroup.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-cgroup.sgml" ;;
+    "doc/ko/lxc-checkconfig.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-checkconfig.sgml" ;;
+    "doc/ko/lxc-checkpoint.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-checkpoint.sgml" ;;
+    "doc/ko/lxc-clone.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-clone.sgml" ;;
+    "doc/ko/lxc-config.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-config.sgml" ;;
+    "doc/ko/lxc-console.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-console.sgml" ;;
+    "doc/ko/lxc-copy.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-copy.sgml" ;;
+    "doc/ko/lxc-create.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-create.sgml" ;;
+    "doc/ko/lxc-destroy.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-destroy.sgml" ;;
+    "doc/ko/lxc-device.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-device.sgml" ;;
+    "doc/ko/lxc-execute.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-execute.sgml" ;;
+    "doc/ko/lxc-freeze.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-freeze.sgml" ;;
+    "doc/ko/lxc-info.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-info.sgml" ;;
+    "doc/ko/lxc-ls.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-ls.sgml" ;;
+    "doc/ko/lxc-monitor.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-monitor.sgml" ;;
+    "doc/ko/lxc-snapshot.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-snapshot.sgml" ;;
+    "doc/ko/lxc-start-ephemeral.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-start-ephemeral.sgml" ;;
+    "doc/ko/lxc-start.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-start.sgml" ;;
+    "doc/ko/lxc-stop.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-stop.sgml" ;;
+    "doc/ko/lxc-top.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-top.sgml" ;;
+    "doc/ko/lxc-unfreeze.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-unfreeze.sgml" ;;
+    "doc/ko/lxc-unshare.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-unshare.sgml" ;;
+    "doc/ko/lxc-user-nic.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-user-nic.sgml" ;;
+    "doc/ko/lxc-usernsexec.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-usernsexec.sgml" ;;
+    "doc/ko/lxc-wait.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-wait.sgml" ;;
+    "doc/ko/lxc.conf.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc.conf.sgml" ;;
+    "doc/ko/lxc.container.conf.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc.container.conf.sgml" ;;
+    "doc/ko/lxc.system.conf.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc.system.conf.sgml" ;;
+    "doc/ko/lxc-usernet.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc-usernet.sgml" ;;
+    "doc/ko/lxc.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/lxc.sgml" ;;
+    "doc/ko/common_options.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/common_options.sgml" ;;
+    "doc/ko/see_also.sgml") CONFIG_FILES="$CONFIG_FILES doc/ko/see_also.sgml" ;;
     "hooks/Makefile") CONFIG_FILES="$CONFIG_FILES hooks/Makefile" ;;
     "templates/Makefile") CONFIG_FILES="$CONFIG_FILES templates/Makefile" ;;
     "templates/lxc-alpine") CONFIG_FILES="$CONFIG_FILES templates/lxc-alpine" ;;
     "templates/lxc-opensuse") CONFIG_FILES="$CONFIG_FILES templates/lxc-opensuse" ;;
     "templates/lxc-oracle") CONFIG_FILES="$CONFIG_FILES templates/lxc-oracle" ;;
     "templates/lxc-plamo") CONFIG_FILES="$CONFIG_FILES templates/lxc-plamo" ;;
+    "templates/lxc-slackware") CONFIG_FILES="$CONFIG_FILES templates/lxc-slackware" ;;
     "templates/lxc-sshd") CONFIG_FILES="$CONFIG_FILES templates/lxc-sshd" ;;
     "templates/lxc-ubuntu") CONFIG_FILES="$CONFIG_FILES templates/lxc-ubuntu" ;;
     "templates/lxc-ubuntu-cloud") CONFIG_FILES="$CONFIG_FILES templates/lxc-ubuntu-cloud" ;;
+    "templates/lxc-sparclinux") CONFIG_FILES="$CONFIG_FILES templates/lxc-sparclinux" ;;
     "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
     "src/lxc/Makefile") CONFIG_FILES="$CONFIG_FILES src/lxc/Makefile" ;;
     "src/lxc/lxc-checkconfig") CONFIG_FILES="$CONFIG_FILES src/lxc/lxc-checkconfig" ;;
-    "src/lxc/lxc-ls") CONFIG_FILES="$CONFIG_FILES src/lxc/lxc-ls" ;;
     "src/lxc/lxc-start-ephemeral") CONFIG_FILES="$CONFIG_FILES src/lxc/lxc-start-ephemeral" ;;
-    "src/lxc/legacy/lxc-ls") CONFIG_FILES="$CONFIG_FILES src/lxc/legacy/lxc-ls" ;;
     "src/lxc/lxc.functions") CONFIG_FILES="$CONFIG_FILES src/lxc/lxc.functions" ;;
     "src/lxc/version.h") CONFIG_FILES="$CONFIG_FILES src/lxc/version.h" ;;
     "src/python-lxc/Makefile") CONFIG_FILES="$CONFIG_FILES src/python-lxc/Makefile" ;;
index 277de4d..84f8699 100644 (file)
@@ -1,10 +1,11 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
-m4_define([lxc_version_major], 1)
-m4_define([lxc_version_minor], 1)
-m4_define([lxc_version_micro], 5)
+m4_define([lxc_version_major], 2)
+m4_define([lxc_version_minor], 0)
+m4_define([lxc_version_micro], 0)
 m4_define([lxc_version_beta], [])
+m4_define([lxc_version_abi], 1.2.0)
 
 m4_define([lxc_version_base], [lxc_version_major.lxc_version_minor.lxc_version_micro])
 m4_define([lxc_version],
@@ -21,6 +22,7 @@ AC_SUBST(LXC_VERSION_BETA, lxc_version_beta)
 AC_SUBST([LXC_VERSION_MAJOR], [lxc_version_major])
 AC_SUBST([LXC_VERSION_MINOR], [lxc_version_minor])
 AC_SUBST([LXC_VERSION_MICRO], [lxc_version_micro])
+AC_SUBST([LXC_VERSION_ABI], [lxc_version_abi])
 AC_SUBST([LXC_VERSION], [lxc_version])
 
 AC_CONFIG_SRCDIR([configure.ac])
@@ -34,13 +36,14 @@ AC_GNU_SOURCE
 # Detect the distribution. This is used for the default configuration and
 # for some distro-specific build options.
 AC_MSG_CHECKING([host distribution])
-AC_ARG_WITH(distro, AS_HELP_STRING([--with-distro=DISTRO], [Specify the Linux distribution to target: One of redhat, oracle, centos, fedora, suse, gentoo, debian, arch, slackware, paldo, openmandriva or pardus.]))
+AC_ARG_WITH(distro, AS_HELP_STRING([--with-distro=DISTRO], [Specify the Linux distribution to target: One of redhat, oracle, centos, fedora, suse, gentoo, debian, arch, slackware, plamo, paldo, openmandriva, pardus, sparclinux, altlinux.]))
 if type lsb_release >/dev/null 2>&1 && test "z$with_distro" = "z"; then
        with_distro=`lsb_release -is`
 fi
 if test "z$with_distro" = "z"; then
        AC_CHECK_FILE(/etc/redhat-release,with_distro="redhat")
        AC_CHECK_FILE(/etc/oracle-release,with_distro="oracle")
+       AC_CHECK_FILE(/etc/sparclinux-release,with_distro="sparclinux")
        AC_CHECK_FILE(/etc/centos-release,with_distro="centos")
        AC_CHECK_FILE(/etc/fedora-release,with_distro="fedora")
        AC_CHECK_FILE(/etc/SuSE-release,with_distro="suse")
@@ -48,13 +51,19 @@ if test "z$with_distro" = "z"; then
        AC_CHECK_FILE(/etc/debian_version,with_distro="debian")
        AC_CHECK_FILE(/etc/arch-release,with_distro="arch")
        AC_CHECK_FILE(/etc/slackware-version,with_distro="slackware")
+       AC_CHECK_FILE(/etc/plamo-version,with_distro="plamo")
        AC_CHECK_FILE(/etc/frugalware-release,with_distro="frugalware")
        AC_CHECK_FILE(/etc/mandrakelinux-release, with_distro="openmandriva")
        AC_CHECK_FILE(/etc/mandriva-release,with_distro="openmandriva")
        AC_CHECK_FILE(/etc/pardus-release,with_distro="pardus")
+       AC_CHECK_FILE(/etc/altlinux-release,with_distro="altlinux")
 fi
 with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]'`
 
+if test "z$with_distro" = "zforsparc"; then
+       with_distro="sparclinux"
+fi
+
 if test "z$with_distro" = "z"; then
        with_distro="unknown"
 fi
@@ -63,7 +72,7 @@ case $with_distro in
                distroconf=default.conf.lxcbr
                distrosysconf="$sysconfdir/default"
                ;;
-       redhat|centos|fedora|oracle|oracleserver|suse|opensuse*)
+       redhat|centos|fedora|oracle|oracleserver|sparclinux|altlinux|suse|opensuse*|plamo)
                distroconf=default.conf.lxcbr
                distrosysconf="$sysconfdir/sysconfig"
                ;;
@@ -87,10 +96,10 @@ AC_ARG_WITH([init-script],
 case "$with_init_script" in
        distro)
                case $with_distro in
-                       fedora|opensuse*)
+                       fedora|altlinux|opensuse*)
                                init_script=systemd
                                ;;
-                       redhat|centos|oracle|oracleserver)
+                       redhat|centos|oracle|oracleserver|sparclinux|plamo)
                                init_script=sysvinit
                                ;;
                        debian|raspbian)
@@ -139,6 +148,13 @@ if test "x$with_systemdsystemunitdir" != "xno"; then
   AC_SUBST([SYSTEMD_UNIT_DIR], [$with_systemdsystemunitdir])
 fi
 
+# Allow enabling deprecated executables
+AC_ARG_ENABLE([deprecated],
+       [AC_HELP_STRING([--enable-deprecated],
+       [enable deprecated executables [default=no]])],
+       [], [enable_deprecated=false])
+AM_CONDITIONAL([ENABLE_DEPRECATED], [test "x$enable_deprecated" = "xyes"])
+
 # Allow disabling rpath
 AC_ARG_ENABLE([rpath],
        [AC_HELP_STRING([--enable-rpath], [set rpath in executables [default=no]])],
@@ -539,6 +555,7 @@ AS_AC_EXPAND(LXCROOTFSMOUNT, "$with_rootfs_path")
 AS_AC_EXPAND(LXCTEMPLATEDIR, "$datadir/lxc/templates")
 AS_AC_EXPAND(LXCTEMPLATECONFIG, "$datadir/lxc/config")
 AS_AC_EXPAND(LXCHOOKDIR, "$datadir/lxc/hooks")
+AS_AC_EXPAND(LXCBINHOOKDIR, "$libexecdir/lxc/hooks")
 AS_AC_EXPAND(LXCINITDIR, "$libexecdir")
 AS_AC_EXPAND(LOGPATH, "$with_log_path")
 AS_AC_EXPAND(RUNTIME_PATH, "$with_runtime_path")
@@ -588,6 +605,10 @@ AC_CHECK_FUNCS([getline],
        AM_CONDITIONAL(HAVE_GETLINE, true)
        AC_DEFINE(HAVE_GETLINE,1,[Have getline]),
        AM_CONDITIONAL(HAVE_GETLINE, false))
+AC_CHECK_FUNCS([getsubopt],
+       AM_CONDITIONAL(HAVE_GETSUBOPT, true)
+       AC_DEFINE(HAVE_GETSUBOPT,1,[Have getsubopt]),
+       AM_CONDITIONAL(HAVE_GETSUBOPT, false))
 AC_CHECK_FUNCS([fgetln],
        AM_CONDITIONAL(HAVE_FGETLN, true)
        AC_DEFINE(HAVE_FGETLN,1,[Have fgetln]),
@@ -625,14 +646,18 @@ AC_CONFIG_FILES([
        config/init/common/lxc-net
        config/init/systemd/Makefile
        config/init/systemd/lxc.service
+       config/init/systemd/lxc@.service
        config/init/systemd/lxc-net.service
        config/init/sysvinit/Makefile
        config/init/sysvinit/lxc-containers
        config/init/sysvinit/lxc-net
+       config/init/upstart/lxc.conf
        config/init/upstart/lxc-net.conf
        config/init/upstart/Makefile
        config/etc/Makefile
        config/templates/Makefile
+       config/templates/alpine.common.conf
+       config/templates/alpine.userns.conf
        config/templates/archlinux.common.conf
        config/templates/archlinux.userns.conf
        config/templates/centos.common.conf
@@ -653,6 +678,8 @@ AC_CONFIG_FILES([
        config/templates/oracle.userns.conf
        config/templates/plamo.common.conf
        config/templates/plamo.userns.conf
+       config/templates/slackware.common.conf
+       config/templates/slackware.userns.conf
        config/templates/ubuntu-cloud.common.conf
        config/templates/ubuntu-cloud.lucid.conf
        config/templates/ubuntu-cloud.userns.conf
@@ -660,6 +687,8 @@ AC_CONFIG_FILES([
        config/templates/ubuntu.lucid.conf
        config/templates/ubuntu.userns.conf
        config/templates/openwrt.common.conf
+       config/templates/sparclinux.common.conf
+       config/templates/sparclinux.userns.conf
        config/templates/userns.conf
        config/yum/Makefile
        config/sysconfig/Makefile
@@ -667,7 +696,6 @@ AC_CONFIG_FILES([
 
        doc/Makefile
        doc/api/Makefile
-       doc/legacy/lxc-ls.sgml
        doc/lxc-attach.sgml
        doc/lxc-autostart.sgml
        doc/lxc-cgroup.sgml
@@ -676,6 +704,7 @@ AC_CONFIG_FILES([
        doc/lxc-clone.sgml
        doc/lxc-config.sgml
        doc/lxc-console.sgml
+       doc/lxc-copy.sgml
        doc/lxc-create.sgml
        doc/lxc-destroy.sgml
        doc/lxc-device.sgml
@@ -715,7 +744,6 @@ AC_CONFIG_FILES([
        doc/examples/lxc-complex.conf
 
        doc/ja/Makefile
-       doc/ja/legacy/lxc-ls.sgml
        doc/ja/lxc-attach.sgml
        doc/ja/lxc-autostart.sgml
        doc/ja/lxc-cgroup.sgml
@@ -724,6 +752,7 @@ AC_CONFIG_FILES([
        doc/ja/lxc-clone.sgml
        doc/ja/lxc-config.sgml
        doc/ja/lxc-console.sgml
+       doc/ja/lxc-copy.sgml
        doc/ja/lxc-create.sgml
        doc/ja/lxc-destroy.sgml
        doc/ja/lxc-device.sgml
@@ -751,6 +780,43 @@ AC_CONFIG_FILES([
        doc/ja/common_options.sgml
        doc/ja/see_also.sgml
 
+       doc/ko/Makefile
+       doc/ko/lxc-attach.sgml
+       doc/ko/lxc-autostart.sgml
+       doc/ko/lxc-cgroup.sgml
+       doc/ko/lxc-checkconfig.sgml
+       doc/ko/lxc-checkpoint.sgml
+       doc/ko/lxc-clone.sgml
+       doc/ko/lxc-config.sgml
+       doc/ko/lxc-console.sgml
+       doc/ko/lxc-copy.sgml
+       doc/ko/lxc-create.sgml
+       doc/ko/lxc-destroy.sgml
+       doc/ko/lxc-device.sgml
+       doc/ko/lxc-execute.sgml
+       doc/ko/lxc-freeze.sgml
+       doc/ko/lxc-info.sgml
+       doc/ko/lxc-ls.sgml
+       doc/ko/lxc-monitor.sgml
+       doc/ko/lxc-snapshot.sgml
+       doc/ko/lxc-start-ephemeral.sgml
+       doc/ko/lxc-start.sgml
+       doc/ko/lxc-stop.sgml
+       doc/ko/lxc-top.sgml
+       doc/ko/lxc-unfreeze.sgml
+       doc/ko/lxc-unshare.sgml
+       doc/ko/lxc-user-nic.sgml
+       doc/ko/lxc-usernsexec.sgml
+       doc/ko/lxc-wait.sgml
+
+       doc/ko/lxc.conf.sgml
+       doc/ko/lxc.container.conf.sgml
+       doc/ko/lxc.system.conf.sgml
+       doc/ko/lxc-usernet.sgml
+       doc/ko/lxc.sgml
+       doc/ko/common_options.sgml
+       doc/ko/see_also.sgml
+
        hooks/Makefile
 
        templates/Makefile
@@ -768,16 +834,16 @@ AC_CONFIG_FILES([
        templates/lxc-opensuse
        templates/lxc-oracle
        templates/lxc-plamo
+       templates/lxc-slackware
        templates/lxc-sshd
        templates/lxc-ubuntu
        templates/lxc-ubuntu-cloud
+       templates/lxc-sparclinux
 
        src/Makefile
        src/lxc/Makefile
        src/lxc/lxc-checkconfig
-       src/lxc/lxc-ls
        src/lxc/lxc-start-ephemeral
-       src/lxc/legacy/lxc-ls
        src/lxc/lxc.functions
        src/lxc/version.h
        src/python-lxc/Makefile
index 0e65d35..b0f8115 100644 (file)
@@ -1,8 +1,8 @@
 SUBDIRS = examples rootfs
-DIST_SUBDIRS = examples rootfs ja api
+DIST_SUBDIRS = examples rootfs ja ko api
 
 if USE_DOCBOOK2X
-SUBDIRS += ja
+SUBDIRS += ja ko
 endif
 
 if ENABLE_API_DOCS
@@ -21,14 +21,16 @@ man_MANS = \
        lxc-cgroup.1 \
        lxc-checkconfig.1 \
        lxc-checkpoint.1 \
-       lxc-clone.1 \
        lxc-config.1 \
        lxc-console.1 \
+       lxc-copy.1 \
        lxc-create.1 \
        lxc-destroy.1 \
+       lxc-device.1 \
        lxc-execute.1 \
        lxc-freeze.1 \
        lxc-info.1 \
+       lxc-ls.1 \
        lxc-monitor.1 \
        lxc-snapshot.1 \
        lxc-start.1 \
@@ -47,12 +49,11 @@ man_MANS = \
        \
        lxc.7
 
+if ENABLE_DEPRECATED
+    man_MANS += lxc-clone.1
 if ENABLE_PYTHON
-    man_MANS += lxc-device.1
-    man_MANS += lxc-ls.1
     man_MANS += lxc-start-ephemeral.1
-else
-    man_MANS += legacy/lxc-ls.1
+endif
 endif
 
 %.1 : %.sgml
index 1ab8c6c..e3f8f9e 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -77,43 +87,22 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@USE_DOCBOOK2X_TRUE@am__append_1 = ja
+@USE_DOCBOOK2X_TRUE@am__append_1 = ja ko
 @ENABLE_API_DOCS_TRUE@am__append_2 = api
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@am__append_3 = lxc-device.1 \
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@      lxc-ls.1 \
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@      lxc-start-ephemeral.1
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_FALSE@am__append_4 = legacy/lxc-ls.1
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@am__append_3 = lxc-clone.1
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@am__append_4 = lxc-start-ephemeral.1
 subdir = doc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-attach.sgml.in $(srcdir)/lxc-autostart.sgml.in \
-       $(srcdir)/lxc-cgroup.sgml.in $(srcdir)/lxc-checkconfig.sgml.in \
-       $(srcdir)/lxc-checkpoint.sgml.in $(srcdir)/lxc-clone.sgml.in \
-       $(srcdir)/lxc-config.sgml.in $(srcdir)/lxc-console.sgml.in \
-       $(srcdir)/lxc-create.sgml.in $(srcdir)/lxc-destroy.sgml.in \
-       $(srcdir)/lxc-device.sgml.in $(srcdir)/lxc-execute.sgml.in \
-       $(srcdir)/lxc-freeze.sgml.in $(srcdir)/lxc-info.sgml.in \
-       $(srcdir)/lxc-ls.sgml.in $(srcdir)/lxc-monitor.sgml.in \
-       $(srcdir)/lxc-snapshot.sgml.in \
-       $(srcdir)/lxc-start-ephemeral.sgml.in \
-       $(srcdir)/lxc-start.sgml.in $(srcdir)/lxc-stop.sgml.in \
-       $(srcdir)/lxc-top.sgml.in $(srcdir)/lxc-unfreeze.sgml.in \
-       $(srcdir)/lxc-unshare.sgml.in $(srcdir)/lxc-user-nic.sgml.in \
-       $(srcdir)/lxc-usernsexec.sgml.in $(srcdir)/lxc-wait.sgml.in \
-       $(srcdir)/lxc.conf.sgml.in \
-       $(srcdir)/lxc.container.conf.sgml.in \
-       $(srcdir)/lxc.system.conf.sgml.in \
-       $(srcdir)/lxc-usernet.sgml.in $(srcdir)/lxc.sgml.in \
-       $(srcdir)/common_options.sgml.in $(srcdir)/see_also.sgml.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-attach.sgml lxc-autostart.sgml \
        lxc-cgroup.sgml lxc-checkconfig.sgml lxc-checkpoint.sgml \
-       lxc-clone.sgml lxc-config.sgml lxc-console.sgml \
+       lxc-clone.sgml lxc-config.sgml lxc-console.sgml lxc-copy.sgml \
        lxc-create.sgml lxc-destroy.sgml lxc-device.sgml \
        lxc-execute.sgml lxc-freeze.sgml lxc-info.sgml lxc-ls.sgml \
        lxc-monitor.sgml lxc-snapshot.sgml lxc-start-ephemeral.sgml \
@@ -211,6 +200,25 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+       $(srcdir)/common_options.sgml.in $(srcdir)/lxc-attach.sgml.in \
+       $(srcdir)/lxc-autostart.sgml.in $(srcdir)/lxc-cgroup.sgml.in \
+       $(srcdir)/lxc-checkconfig.sgml.in \
+       $(srcdir)/lxc-checkpoint.sgml.in $(srcdir)/lxc-clone.sgml.in \
+       $(srcdir)/lxc-config.sgml.in $(srcdir)/lxc-console.sgml.in \
+       $(srcdir)/lxc-copy.sgml.in $(srcdir)/lxc-create.sgml.in \
+       $(srcdir)/lxc-destroy.sgml.in $(srcdir)/lxc-device.sgml.in \
+       $(srcdir)/lxc-execute.sgml.in $(srcdir)/lxc-freeze.sgml.in \
+       $(srcdir)/lxc-info.sgml.in $(srcdir)/lxc-ls.sgml.in \
+       $(srcdir)/lxc-monitor.sgml.in $(srcdir)/lxc-snapshot.sgml.in \
+       $(srcdir)/lxc-start-ephemeral.sgml.in \
+       $(srcdir)/lxc-start.sgml.in $(srcdir)/lxc-stop.sgml.in \
+       $(srcdir)/lxc-top.sgml.in $(srcdir)/lxc-unfreeze.sgml.in \
+       $(srcdir)/lxc-unshare.sgml.in $(srcdir)/lxc-user-nic.sgml.in \
+       $(srcdir)/lxc-usernet.sgml.in $(srcdir)/lxc-usernsexec.sgml.in \
+       $(srcdir)/lxc-wait.sgml.in $(srcdir)/lxc.conf.sgml.in \
+       $(srcdir)/lxc.container.conf.sgml.in $(srcdir)/lxc.sgml.in \
+       $(srcdir)/lxc.system.conf.sgml.in $(srcdir)/see_also.sgml.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -288,6 +296,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -301,6 +310,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -392,6 +402,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -401,7 +412,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 SUBDIRS = examples rootfs $(am__append_1) $(am__append_2)
-DIST_SUBDIRS = examples rootfs ja api
+DIST_SUBDIRS = examples rootfs ja ko api
 EXTRA_DIST = \
        lxc.container.conf \
        lxc.system.conf \
@@ -409,9 +420,10 @@ EXTRA_DIST = \
 
 @ENABLE_DOCBOOK_TRUE@man_MANS = lxc-attach.1 lxc-autostart.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-cgroup.1 lxc-checkconfig.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-checkpoint.1 lxc-clone.1 lxc-config.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-console.1 lxc-create.1 lxc-destroy.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-execute.1 lxc-freeze.1 lxc-info.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-checkpoint.1 lxc-config.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-console.1 lxc-copy.1 lxc-create.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-destroy.1 lxc-device.1 lxc-execute.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-freeze.1 lxc-info.1 lxc-ls.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-monitor.1 lxc-snapshot.1 lxc-start.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-stop.1 lxc-top.1 lxc-unfreeze.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-unshare.1 lxc-user-nic.1 \
@@ -434,7 +446,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu doc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -468,6 +479,8 @@ lxc-config.sgml: $(top_builddir)/config.status $(srcdir)/lxc-config.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-console.sgml: $(top_builddir)/config.status $(srcdir)/lxc-console.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-copy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-copy.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-create.sgml: $(top_builddir)/config.status $(srcdir)/lxc-create.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-destroy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-destroy.sgml.in
@@ -925,6 +938,8 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man7
        pdf-am ps ps-am tags tags-am uninstall uninstall-am \
        uninstall-man uninstall-man1 uninstall-man5 uninstall-man7
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_DOCBOOK_TRUE@%.1 : %.sgml
 @ENABLE_DOCBOOK_TRUE@  $(db2xman) $<
index ef8599e..7192d37 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,12 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = doc/api
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -108,6 +118,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -160,6 +171,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -173,6 +185,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -264,6 +277,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -288,7 +302,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/api/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu doc/api/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -457,6 +470,8 @@ uninstall-am:
        mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \
        uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_API_DOCS_TRUE@html: Doxyfile
 @ENABLE_API_DOCS_TRUE@ doxygen
index 13fac90..c48a0e1 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,16 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = doc/examples
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-macvlan.conf.in $(srcdir)/lxc-vlan.conf.in \
-       $(srcdir)/lxc-no-netns.conf.in \
-       $(srcdir)/lxc-empty-netns.conf.in $(srcdir)/lxc-phys.conf.in \
-       $(srcdir)/lxc-veth.conf.in $(srcdir)/lxc-complex.conf.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-macvlan.conf lxc-vlan.conf lxc-no-netns.conf \
@@ -144,6 +150,11 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(pkgexamplesdir)"
 DATA = $(noinst_DATA) $(pkgexamples_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-complex.conf.in \
+       $(srcdir)/lxc-empty-netns.conf.in \
+       $(srcdir)/lxc-macvlan.conf.in $(srcdir)/lxc-no-netns.conf.in \
+       $(srcdir)/lxc-phys.conf.in $(srcdir)/lxc-veth.conf.in \
+       $(srcdir)/lxc-vlan.conf.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -196,6 +207,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -209,6 +221,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -300,6 +313,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -353,7 +367,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/examples/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu doc/examples/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -560,6 +573,8 @@ uninstall-am: uninstall-pkgexamplesDATA
        pdf-am ps ps-am tags-am uninstall uninstall-am \
        uninstall-pkgexamplesDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 20a7021..201094b 100644 (file)
@@ -13,14 +13,16 @@ man_MANS = \
        lxc-cgroup.1 \
        lxc-checkconfig.1 \
        lxc-checkpoint.1 \
-       lxc-clone.1 \
        lxc-config.1 \
        lxc-console.1 \
+       lxc-copy.1 \
        lxc-create.1 \
        lxc-destroy.1 \
+       lxc-device.1 \
        lxc-execute.1 \
        lxc-freeze.1 \
        lxc-info.1 \
+       lxc-ls.1 \
        lxc-monitor.1 \
        lxc-snapshot.1 \
        lxc-start.1 \
@@ -39,12 +41,11 @@ man_MANS = \
        \
        lxc.7
 
+if ENABLE_DEPRECATED
+    man_MANS += lxc-clone.1
 if ENABLE_PYTHON
-    man_MANS += lxc-device.1
-    man_MANS += lxc-ls.1
     man_MANS += lxc-start-ephemeral.1
-else
-    man_MANS += legacy/lxc-ls.1
+endif
 endif
 
 %.1 : %.sgml
index 910dcbf..1f2a40f 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -77,41 +87,20 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@am__append_1 = lxc-device.1 \
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@      lxc-ls.1 \
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@      lxc-start-ephemeral.1
-@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_FALSE@am__append_2 = legacy/lxc-ls.1
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@am__append_1 = lxc-clone.1
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@am__append_2 = lxc-start-ephemeral.1
 subdir = doc/ja
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-attach.sgml.in $(srcdir)/lxc-autostart.sgml.in \
-       $(srcdir)/lxc-cgroup.sgml.in $(srcdir)/lxc-checkconfig.sgml.in \
-       $(srcdir)/lxc-checkpoint.sgml.in $(srcdir)/lxc-clone.sgml.in \
-       $(srcdir)/lxc-config.sgml.in $(srcdir)/lxc-console.sgml.in \
-       $(srcdir)/lxc-create.sgml.in $(srcdir)/lxc-destroy.sgml.in \
-       $(srcdir)/lxc-device.sgml.in $(srcdir)/lxc-execute.sgml.in \
-       $(srcdir)/lxc-freeze.sgml.in $(srcdir)/lxc-info.sgml.in \
-       $(srcdir)/lxc-ls.sgml.in $(srcdir)/lxc-monitor.sgml.in \
-       $(srcdir)/lxc-snapshot.sgml.in \
-       $(srcdir)/lxc-start-ephemeral.sgml.in \
-       $(srcdir)/lxc-start.sgml.in $(srcdir)/lxc-stop.sgml.in \
-       $(srcdir)/lxc-top.sgml.in $(srcdir)/lxc-unfreeze.sgml.in \
-       $(srcdir)/lxc-unshare.sgml.in $(srcdir)/lxc-user-nic.sgml.in \
-       $(srcdir)/lxc-usernsexec.sgml.in $(srcdir)/lxc-wait.sgml.in \
-       $(srcdir)/lxc.conf.sgml.in \
-       $(srcdir)/lxc.container.conf.sgml.in \
-       $(srcdir)/lxc.system.conf.sgml.in \
-       $(srcdir)/lxc-usernet.sgml.in $(srcdir)/lxc.sgml.in \
-       $(srcdir)/common_options.sgml.in $(srcdir)/see_also.sgml.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-attach.sgml lxc-autostart.sgml \
        lxc-cgroup.sgml lxc-checkconfig.sgml lxc-checkpoint.sgml \
-       lxc-clone.sgml lxc-config.sgml lxc-console.sgml \
+       lxc-clone.sgml lxc-config.sgml lxc-console.sgml lxc-copy.sgml \
        lxc-create.sgml lxc-destroy.sgml lxc-device.sgml \
        lxc-execute.sgml lxc-freeze.sgml lxc-info.sgml lxc-ls.sgml \
        lxc-monitor.sgml lxc-snapshot.sgml lxc-start-ephemeral.sgml \
@@ -209,6 +198,25 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+       $(srcdir)/common_options.sgml.in $(srcdir)/lxc-attach.sgml.in \
+       $(srcdir)/lxc-autostart.sgml.in $(srcdir)/lxc-cgroup.sgml.in \
+       $(srcdir)/lxc-checkconfig.sgml.in \
+       $(srcdir)/lxc-checkpoint.sgml.in $(srcdir)/lxc-clone.sgml.in \
+       $(srcdir)/lxc-config.sgml.in $(srcdir)/lxc-console.sgml.in \
+       $(srcdir)/lxc-copy.sgml.in $(srcdir)/lxc-create.sgml.in \
+       $(srcdir)/lxc-destroy.sgml.in $(srcdir)/lxc-device.sgml.in \
+       $(srcdir)/lxc-execute.sgml.in $(srcdir)/lxc-freeze.sgml.in \
+       $(srcdir)/lxc-info.sgml.in $(srcdir)/lxc-ls.sgml.in \
+       $(srcdir)/lxc-monitor.sgml.in $(srcdir)/lxc-snapshot.sgml.in \
+       $(srcdir)/lxc-start-ephemeral.sgml.in \
+       $(srcdir)/lxc-start.sgml.in $(srcdir)/lxc-stop.sgml.in \
+       $(srcdir)/lxc-top.sgml.in $(srcdir)/lxc-unfreeze.sgml.in \
+       $(srcdir)/lxc-unshare.sgml.in $(srcdir)/lxc-user-nic.sgml.in \
+       $(srcdir)/lxc-usernet.sgml.in $(srcdir)/lxc-usernsexec.sgml.in \
+       $(srcdir)/lxc-wait.sgml.in $(srcdir)/lxc.conf.sgml.in \
+       $(srcdir)/lxc.container.conf.sgml.in $(srcdir)/lxc.sgml.in \
+       $(srcdir)/lxc.system.conf.sgml.in $(srcdir)/see_also.sgml.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -286,6 +294,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -299,6 +308,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -390,6 +400,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -405,9 +416,10 @@ EXTRA_DIST = \
 
 @ENABLE_DOCBOOK_TRUE@man_MANS = lxc-attach.1 lxc-autostart.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-cgroup.1 lxc-checkconfig.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-checkpoint.1 lxc-clone.1 lxc-config.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-console.1 lxc-create.1 lxc-destroy.1 \
-@ENABLE_DOCBOOK_TRUE@  lxc-execute.1 lxc-freeze.1 lxc-info.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-checkpoint.1 lxc-config.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-console.1 lxc-copy.1 lxc-create.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-destroy.1 lxc-device.1 lxc-execute.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-freeze.1 lxc-info.1 lxc-ls.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-monitor.1 lxc-snapshot.1 lxc-start.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-stop.1 lxc-top.1 lxc-unfreeze.1 \
 @ENABLE_DOCBOOK_TRUE@  lxc-unshare.1 lxc-user-nic.1 \
@@ -430,7 +442,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/ja/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu doc/ja/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -464,6 +475,8 @@ lxc-config.sgml: $(top_builddir)/config.status $(srcdir)/lxc-config.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-console.sgml: $(top_builddir)/config.status $(srcdir)/lxc-console.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-copy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-copy.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-create.sgml: $(top_builddir)/config.status $(srcdir)/lxc-create.sgml.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-destroy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-destroy.sgml.in
@@ -921,6 +934,8 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man7
        pdf-am ps ps-am tags tags-am uninstall uninstall-am \
        uninstall-man uninstall-man1 uninstall-man5 uninstall-man7
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_DOCBOOK_TRUE@%.1 : %.sgml
 @ENABLE_DOCBOOK_TRUE@  $(db2xman) --encoding=UTF-8 $<
diff --git a/doc/ja/legacy/lxc-ls.sgml.in b/doc/ja/legacy/lxc-ls.sgml.in
deleted file mode 100644 (file)
index 0fdfafd..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-<!--
-
-lxc: linux Container library
-
-(C) Copyright IBM Corp. 2007, 2008
-
-Authors:
-Daniel Lezcano <dlezcano at fr.ibm.com>
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Translated into Japanese
-by KATOH Yasufumi <karma at jazz.email.ne.jp>
-
--->
-
-<!DOCTYPE refentry PUBLIC @docdtd@ [
-
-<!ENTITY seealso SYSTEM "@builddir@/../see_also.sgml">
-]>
-
-<refentry>
-
-  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
-
-  <refmeta>
-    <refentrytitle>lxc-ls</refentrytitle>
-    <manvolnum>1</manvolnum>
-  </refmeta>
-
-  <refnamediv>
-    <refname>lxc-ls</refname>
-
-    <refpurpose>
-      <!--
-      list the containers existing on the system
-      -->
-      システム上に存在するコンテナをリスト表示する。
-    </refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>lxc-ls</command>
-      <arg choice="opt">--active</arg>
-      <arg choice="opt">ls option</arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title><!-- Description -->説明</title>
-    <para>
-      <!--
-      <command>lxc-ls</command> list the containers existing on the
-      system.
-      -->
-      <command>lxc-ls</command> はシステム上に存在するコンテナをリスト表示します。
-    </para>
-  </refsect1>
-
-  <refsect1>
-    <title><!-- Options -->オプション</title>
-    <variablelist>
-
-      <varlistentry>
-       <term>
-         <option><optional>--active</optional></option>
-       </term>
-       <listitem>
-         <para>
-            <!--
-           List active containers.
-            -->
-            稼働中のコンテナをリスト表示します。
-         </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>
-         <option><optional>ls options</optional></option>
-       </term>
-       <listitem>
-         <para>
-            <!--
-           The option passed to <command>lxc-ls</command> are the
-           same as the <command>ls</command> command.
-            -->
-            <command>lxc-ls</command> が受け付けるオプションは、<command>ls</command> コマンドと同じです。
-         </para>
-       </listitem>
-      </varlistentry>
-
-    </variablelist>
-
-  </refsect1>
-
-  <refsect1>
-    <title><!-- Examples -->例</title>
-    <variablelist>
-      <varlistentry>
-       <term>lxc-ls -l</term>
-       <listitem>
-       <para>
-          <!--
-         list all the container and their permissions.
-          -->
-          全てのコンテナとそのパーミッションをリスト表示します。
-       </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>lxc-ls --active -1</term>
-       <listitem>
-       <para>
-          <!--
-         list active containers and display the list in one column.
-          -->
-          稼働中のコンテナを一列にリスト表示します。
-       </para>
-       </listitem>
-      </varlistentry>
-
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-
-    <simpara>
-      <citerefentry>
-       <refentrytitle>ls</refentrytitle>
-       <manvolnum>1</manvolnum>
-      </citerefentry>,
-    </simpara>
-
-  </refsect1>
-
-  &seealso;
-
-  <refsect1>
-    <title><!-- Author -->作者</title>
-    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
-  </refsect1>
-
-</refentry>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:2
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-default-dtd-file:nil
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
index 6ebc03c..7f28b62 100644 (file)
@@ -91,6 +91,26 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       もし <replaceable>command</replaceable> が指定されていない場合、<command>lxc-attach</command> コマンドを実行したユーザのデフォルトシェルをコンテナ内で調べて実行します。
       もしコンテナ内にユーザが存在しない場合や、コンテナで nsswitch 機構が働いていない場合はこの動作は失敗します。
     </para>
+    <para>
+      <!--
+    Previous versions of <command>lxc-attach</command> simply attached to the
+    specified namespaces of a container and ran a shell or the specified command
+    without first allocating a pseudo terminal. This made them vulnerable to
+    input faking via a TIOCSTI <command>ioctl</command> call after switching
+    between userspace execution contexts with different privilege levels. Newer
+    versions of <command>lxc-attach</command> will try to allocate a pseudo
+    terminal master/slave pair on the host and attach any standard file
+    descriptors which refer to a terminal to the slave side of the pseudo
+    terminal before executing a shell or command. Note, that if none of the
+    standard file descriptors refer to a terminal <command>lxc-attach</command>
+    will not try to allocate a pseudo terminal. Instead it will simply attach
+    to the containers namespaces and run a shell or the specified command.
+    -->
+      前のバージョンの <command>lxc-attach</command> は、単に指定したコンテナの名前空間にアタッチし、最初に擬似端末 (pseudo terminal) を割り当てないで、シェルもしくは指定したコマンドを実行しました。
+      これは、異なる特権レベルを持つユーザ空間の実行コンテキストを切り替えた後に、TIOCSTI <command>ioctl</command> の呼び出し経由で擬似入力を行うことに対して脆弱となります。
+      新しいバージョンの <command>lxc-attach</command> は、ホスト上の擬似端末のマスター/スレーブのペアを割り当てようとします。そしてシェルやコマンドを実行する前に、擬似端末のスレーブ側に対して、ターミナルを参照する標準ファイルディスクリプタをアタッチします。
+      ターミナルを参照する標準ファイルディスクリプタがない場合は、<command>lxc-attach</command> は擬似端末の割り当てを行わないことに注意してください。代わりに、単にコンテナの名前空間にアタッチし、シェルや指定したコマンドを実行します。
+    </para>
 
   </refsect1>
 
@@ -152,10 +172,13 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            <replaceable>CGROUP|LSM</replaceable>. Allowed values are
            <replaceable>CGROUP</replaceable>, <replaceable>CAP</replaceable> and
            <replaceable>LSM</replaceable> representing cgroup, capabilities and
-           restriction privileges respectively.
+           restriction privileges respectively. (The pipe symbol needs to be escaped,
+           e.g. <replaceable>CGROUP\|LSM</replaceable> or quoted, e.g.
+           <replaceable>"CGROUP|LSM"</replaceable>.)
            -->
             全ての特権の取得したくない場合は、パイプで連結したリストとして、例えば <replaceable>CGROUP|LSM</replaceable> のように、特権を指定することが可能です。
             指定できる値は、それぞれ cgroup、ケーパビリティ、特権の制限を表す <replaceable>CGROUP</replaceable>、<replaceable>CAP</replaceable>、<replaceable>LSM</replaceable> です。
+           (パイプ記号を <replaceable>CGROUP\|LSM</replaceable> のようにエスケープするか、<replaceable>"CGROUP|LSM"</replaceable> のように引用符号を付ける必要があります。)
           </para>
          <para>
             <!--
@@ -191,13 +214,16 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            <replaceable>NETWORK</replaceable>. This allows one to change
            the context of the process to e.g. the network namespace of the
            container while retaining the other namespaces as those of the
-           host.
+            host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
             -->
             アタッチする名前空間をパイプで連結したリストで指定します。
             例えば <replaceable>NETWORK|IPC</replaceable> のようにです。
             ここで使用可能な値は <replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>, <replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>, <replaceable>USER </replaceable>, <replaceable>NETWORK</replaceable> です。
             これにより指定した名前空間にプロセスのコンテキストを変更できます。
             例えばコンテナのネットワーク名前空間に変更する一方で、他の名前空間はホストの名前空間のままにするというような事が可能です。
+           (パイプ記号を <replaceable>MOUNT\|PID</replaceable> のようにエスケープするか、<replaceable>"MOUNT|PID"</replaceable> のように引用符号を付ける必要があります。)
          </para>
          <para>
             <!--
@@ -409,7 +435,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       network/pid namespace context of the attached process. In order
       not to interfere with the host's actual filesystem, the mount
       namespace will be unshared (like <command>lxc-unshare</command>
-      does) before this is done, esentially giving the process a new
+      does) before this is done, essentially giving the process a new
       mount namespace, which is identical to the hosts's mount namespace
       except for the <replaceable>/proc</replaceable> and
       <replaceable>/sys</replaceable> filesystems.
@@ -418,6 +444,21 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       これにより、アタッチするプロセスのネットワーク/pid 名前空間のコンテキストを反映させることができます。ホストの実際のファイルシステムに影響を与えないために、実行前にはマウント名前空間は unshare されます (<command>lxc-unshare</command> のように)。
       これは、<replaceable>/proc</replaceable> と <replaceable>/sys</replaceable> ファイルシステム以外はホストのマウント名前空間と同じである、新しいマウント名前空間がプロセスに与えられるということです。
     </para>
+    <para>
+      <!--
+      Previous versions of <command>lxc-attach</command> suffered a bug whereby
+      a user could attach to a containers namespace without being placed in a
+      writeable cgroup for some critical subsystems. Newer versions of
+      <command>lxc-attach</command> will check whether a user is in a writeable
+      cgroup for those critical subsystems. <command>lxc-attach</command> might
+      thus fail unexpectedly for some users (E.g. on systems where an
+      unprivileged user is not placed in a writeable cgroup in critical
+      subsystems on login.). However, this behavior is correct and more secure.
+      -->
+      以前のバージョンの <command>lxc-attach</command> は、いくつかの重要なサブシステムに対して、書き込み可能な cgroup 内に配置することなしに、ユーザがコンテナの名前空間にアタッチできたバグがありました。
+      新しいバージョンの <command>lxc-attach</command> は、このような重要なサブシステムに対して、ユーザが書き込み可能な cgroup 内にいるかどうかをチェックします。
+      したがって、ユーザによっては <command>lxc-attach</command> は不意に失敗するかもしれません (例えば、非特権ユーザが、ログイン時に重要であるサブシステムの書き込み可能な cgroup に配置されていないようなシステムで)。しかし、この振る舞いは正しく、よりセキュアです。
+    </para>
   </refsect1>
 
   <refsect1>
index 6ad323b..6f62f5a 100644 (file)
@@ -94,7 +94,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option>-D <replacable>PATH</replacable>, --checkpoint-dir=<replacable>PATH</replacable></option>
+          <option>-D <replaceable>PATH</replaceable>, --checkpoint-dir=<replaceable>PATH</replaceable></option>
         </term>
         <listitem>
           <para>
index 963b3a1..9e68910 100644 (file)
@@ -64,6 +64,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
       <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
       <arg choice="req">-o <replaceable>orig</replaceable></arg>
       <arg choice="req">-n <replaceable>new</replaceable></arg>
       <arg choice="opt">-- hook arguments</arg>
@@ -78,6 +79,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
       <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
       <arg choice="req">orig</arg>
       <arg choice="req">new</arg>
       <arg choice="opt">-- hook arguments</arg>
@@ -276,6 +278,21 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
+         <option>-R, --rename</option>
+       </term>
+       <listitem>
+         <para>
+           <!--
+           Rename an existing container.
+           <replaceable>orig</replaceable> is renamed <replaceable>new</replaceable>.
+           -->
+           コンテナの名前を変更します。<replaceable>orig</replaceable> を <replaceable>new</replaceable> という名前に変更します。
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
          <option>-o, --orig <replaceable>orig</replaceable></option>
        </term>
        <listitem>
@@ -331,6 +348,17 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     </para>
   </refsect1>
 
+  <refsect1>
+    <title><!-- Notes -->注意</title>
+    <para>
+      <!--
+    <command>lxc-clone</command> is deprecated in favor of
+    <command>lxc-copy</command>.
+    -->
+      <command>lxc-clone</command> は <command>lxc-copy</command> に置き換えられ、廃止される予定です。
+    </para>
+  </refsect1>
+
   &seealso;
 
   <refsect1>
index 3ab395c..fbf7b7b 100644 (file)
@@ -120,7 +120,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-e <optional><replaceable>escape character</replaceable></optional></option>
+         <option>-e, --escape <replaceable>escape character</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -138,7 +138,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       </varlistentry>
       <varlistentry>
        <term>
-         <option>-t <optional><replaceable>ttynum</replaceable></optional></option>
+         <option>-t, --tty <replaceable>ttynum</replaceable></option>
        </term>
        <listitem>
          <para>
diff --git a/doc/ja/lxc-copy.sgml.in b/doc/ja/lxc-copy.sgml.in
new file mode 100644 (file)
index 0000000..f7ed493
--- /dev/null
@@ -0,0 +1,373 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Inc. 2007, 2008
+
+Authors:
+Christian Brauner <christian.brauner at mailbox.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Japanese
+by KATOH Yasufumi <karma at jazz.email.ne.jp>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-copy</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-copy</refname>
+
+    <refpurpose>
+      <!--
+      copy an existing container.
+      -->
+      既存のコンテナのコピー
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-e, --ephemeral</arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-R, --rename</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->説明</title>
+
+    <para>
+      <!--
+      <command>lxc-copy</command> creates and optionally starts (ephemeral or
+      non-ephemeral) copies of existing containers. It replaces
+      <command>lxc-clone</command> and <command>lxc-start-ephemeral</command>.
+      -->
+      <command>lxc-copy</command> は、すでに存在するコンテナのコピーを作成します。オプションを指定することで、作成後にそのコピーを起動できます (コピーは一時的なコピーまたは永続的なコピーのどちらも可能です)。
+      このコマンドは <command>lxc-clone</command> と <command>lxc-start-ephemeral</command> の置き換えのコマンドです。
+    </para>
+    <para>
+      <!--
+      <command>lxc-copy</command> creates copies of existing containers. Copies
+      can be complete clones of the original container. In this case the whole
+      root filesystem of the container is simply copied to the new container. Or
+      they can be snapshots, i.e. small copy-on-write copies of the original
+      container. In this case the specified backing storage for the copy must
+      support snapshots. This currently includes aufs, btrfs, lvm (lvm devices
+      do not support snapshots of snapshots.), overlay, and zfs.
+      -->
+      <command>lxc-copy</command> は、既存のコンテナのコピーを作成します。
+      コピーは元のコンテナの完全なクローンにできます。この場合、単にコンテナのルートファイルシステムのすべてが、新しいコンテナにコピーされます。
+      また、スナップショットを取得することも可能です。すなわち、元のコンテナの小さなコピーオンライトのコピーにするということです。この場合、コピーで指定するバッキングストレージがスナップショットをサポートしている必要があります。
+      スナップショットをサポートしているバッキングストレージは、現時点では aufs、btrfs、lvm (lvm デバイスはスナップショットのスナップショットはサポートしていません)、overlay、zfs です。
+    </para>
+      
+    <para>
+      <!--
+    The copy's backing storage will be of the same type as the original
+    container. aufs or overlayfs snapshots of directory backed containers are
+    exempted from this rule.
+    -->
+      コピー先のバッキングストレージは、元のコンテナと同じタイプになるでしょう。ただし、ディレクトリバックエンドのコンテナのスナップショットは aufs と overlayfs で取得できますので例外です。
+    </para>
+
+    <para>
+      <!--
+    When the <replaceable>-e</replaceable> flag is specified an ephemeral
+    snapshot of the original container is created and started. Ephemeral
+    containers will have <command>lxc.ephemeral = 1</command> set in their
+    config file and will be destroyed on shutdown. When
+    <replaceable>-e</replaceable> is used in combination with
+    <replaceable>-D</replaceable> a non-ephemeral snapshot of the original
+    container is created and started.
+    -->
+      <replaceable>-e</replaceable> オプションを指定した場合は、元のコンテナの一時的なスナップショットを作成し、起動します。一時的なコンテナの場合、設定ファイルに <command>lxc.ephemeral = 1</command> がセットされ、シャットダウン後に削除されます。
+      <replaceable>-e</replaceable> と <replaceable>-D</replaceable> を同時に指定すると、元のコンテナの一時的ではないスナップショットを作成し、起動します。
+    </para>
+
+    <para>
+      <!--
+    When <replaceable>-e</replaceable> is specified and no newname is given via
+    <replaceable>-N</replaceable> a random name for the snapshot will be chosen.
+    -->
+      <replaceable>-e</replaceable> を指定した場合で、<replaceable>-N</replaceable> でコンテナの名前を指定しない場合は、スナップショットの名前はランダムで命名されます。
+    </para>
+
+    <para>
+      <!--
+    Containers created and started with <replaceable>-e</replaceable> can have
+    custom mounts. These are specified with the <replaceable>-m</replaceable>
+    flag. Currently three types of mounts are supported:
+    <replaceable>aufs</replaceable>, <replaceable>bind</replaceable>, and
+    <replaceable>overlay</replaceable>. Mount types are specified as suboptions
+    to the <replaceable>-m</replaceable> flag and can be specified multiple
+    times separated by commas. <replaceable>aufs</replaceable> and
+    <replaceable>overlay</replaceable> mounts are currently specified in the
+    format <replaceable>-m overlay=/src:/dest</replaceable>.  When no
+    destination <replaceable>dest</replaceable> is specified
+    <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. Read-only <replaceable>bind</replaceable>
+    mounts are specified <replaceable>-m bind=/src:/dest:ro</replaceable> and
+    read-write <replaceable>bind</replaceable> mounts <replaceable>-m
+    bind=/src:/dest:rw</replaceable>. Read-write <replaceable>bind</replaceable>
+    mounts are the default and <replaceable>rw</replaceable> can be missing when
+    a read-write mount is wanted. When <replaceable>dest</replaceable> is
+    missing <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. An example for multiple mounts would be
+    <replaceable>-m
+    bind=/src1:/dest1:ro,bind=/src2:ro,overlay=/src3:/dest3</replaceable>.
+    -->
+      <replaceable>-e</replaceable> で作成し、起動したコンテナは、コンテナ独自のマウントを行えます。現時点では <replaceable>aufs</replaceable>、<replaceable>bind</replaceable>、<replaceable>overlay</replaceable> という 3 つのタイプのマウントがサポートされています。
+      マウントタイプは <replaceable>-m</replaceable> オプションのサブオプションとして指定します。この指定はカンマ区切りで複数回指定できます。
+      <replaceable>aufs</replaceable> と <replaceable>overlay</replaceable> マウントの場合は、現時点では <replaceable>-m overlay=/src:/dest</replaceable> のように指定します。マウント先の <replaceable>dest</replaceable> を指定しない場合は、<replaceable>dest</replaceable> は <replaceable>src</replaceable> と同じになります。
+      読み込み専用の <replaceable>bind</replaceable> マウントは <replaceable>-m bind=/src:/dest:ro</replaceable> のように指定します。読み書き可能な <replaceable>bind</replaceable> マウントは <replaceable>-m bind=/src:/dest:rw</replaceable> のように指定します。<replaceable>bind</replaceable> マウントのデフォルトは読み書き可能ですので、読み書き可能なマウントを行う場合は省略できます。マウント先の <replaceable>dest</replaceable> を指定しない場合は、<replaceable>dest</replaceable> は <replaceable>src</replaceable> と同じになります。
+      複数のマウントを行う場合の例を示すと、<replaceable>-m bind=/src1:/dest1:ro,bind=/src2:ro,overlay=/src3:/dest3</replaceable> のようになります。
+    </para>
+
+    <para>
+      <!--
+    The mounts, their options, and formats supported via the
+    <replaceable>-m</replaceable> flag are subject to change.
+    -->
+      <replaceable>-m</replaceable> オプションで指定するマウント、オプション、指定フォーマットは変更される可能性があります。
+    </para>
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->オプション</title>
+
+    <variablelist>
+
+         <varlistentry>
+           <term> <option>-N,--newname <replaceable>newname</replaceable></option> </term>
+          <listitem>
+           <para><!-- The name for the copy. -->コピー先のコンテナの名前。</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-p,--newpath <replaceable>newpath</replaceable></option> </term>
+          <listitem>
+           <para><!-- The path for the copy. -->コピー先のパス。</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-R,--rename </option> </term>
+          <listitem>
+           <para><!-- Rename the original container. -->元のコンテナをリネームします。</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-s,--snapshot </option> </term>
+          <listitem>
+            <para><!-- Create a snapshot of the original container. The backing
+            storage for the copy must support snapshots. This currently includes
+            aufs, btrfs, lvm, overlay, and zfs. -->
+             元のコンテナのスナップショットを作成します。コピー先のバッキングストレージがスナップショットをサポートしている必要があります。現時点では aufs、btrfs、lvm、overlay、zfs が対象となります。
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-F,--foreground</option> </term>
+          <listitem>
+            <para><!-- Run the snapshot in the foreground. The snapshots console will
+            be attached to the current tty. (This option can only be specified
+            in conjunction with <replaceable>-e</replaceable>.) -->
+             スナップショットしたコンテナをフォアグラウンドで起動します。スナップショットしたコンテナのコンソールは現在の tty にアタッチされます。(このオプションは <replaceable>-e</replaceable> と同時の場合のみ指定できます。)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-d, --daemon</option> </term>
+          <listitem>
+            <para><!-- Run the snapshot as a daemon (This is the default mode for
+            ephemeral containers.). As the container has no more tty, if an
+            error occurs nothing will be displayed, the log file can
+            be used to check the error. (This option can only be specified in
+            conjunction with <replaceable>-e</replaceable>.) -->
+             スナップショットしたコンテナをデーモンで起動します (一時的なコンテナではこのモードがデフォルトです)。
+             コンテナは tty を持ちませんので、エラーが発生しても何も表示されません。エラーをチェックするにはログファイルを使います。(このオプションは <replaceable>-e</replaceable> と同時の場合のみ指定できます。)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-m, --mount <replaceable>mounttype</replaceable></option> </term>
+          <listitem>
+            <para><!--  Specify a mount for a snapshot  The
+            <replaceable>opts</replaceable> argument for the mount type can by
+            of type {aufs, bind, overlay}. For example <option>-m
+            bind=/src:/dest:ro,overlay=/src:/dest</option> (This option can
+            currently only be specified in conjunction with
+            <replaceable>-e</replaceable>.). --></para>
+             スナップショットするコンテナで行うマウントを指定します。マウントタイプは {aufs, bind, overlay} のどれかで指定します。例えば <option>-m bind=/src:/dest:ro,overlay=/src:/dest</option> のようになります。(このオプションは <replaceable>-e</replaceable> と同時の場合のみ指定できます。)
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-B, --backingstorage <replaceable>backingstorage</replaceable></option></term>
+          <listitem>
+            <para><!-- Specify the backing storage type to be used for the copy
+            where 'backingstorage' is of type 'aufs', 'btrfs', 'dir', 'lvm', 'loop',
+            'overlay', or 'zfs'. -->
+             コピー先コンテナのバッキングストレージのタイプを指定します。ここで 'backingsotrage' は 'aufs'、'btrfs'、'dir'、'lvm'、'loop'、'overlay'、'zfs' のどれかです。
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-L, --fssize <replaceable>size [unit]</replaceable></option></term>
+          <listitem>
+            <para><!-- Specify the size for an 'lvm' filesystem. -->'lvm' ファイルシステムのサイズを指定します。</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-D, --keepdata </option></term>
+          <listitem>
+            <para><!-- When this option is specified with
+            <replaceable>-e</replaceable> a non-ephemeral container is created
+            and started. -->
+             <replaceable>-e</replaceable> オプションと同時にこのオプションを使うと、一時的でないコンテナを作成し、起動します。
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-K, --keepname </option></term>
+          <listitem>
+            <para><!-- When this option is specified the hostname of the original
+              container will be kept for the copy. -->
+             このオプションを指定すると、元のコンテナのホスト名をコピー先でもそのまま使います。
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-M, --keepmac </option></term>
+          <listitem>
+            <para><!-- When this option is specified the MAC address of the original
+              container will be kept for the copy. -->
+             このオプションを指定すると、元のコンテナの MAC アドレスをコピー先でもそのまま使います。
+            </para>
+          </listitem>
+         </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Copy hook -->コピー時のフック</title>
+    <para>
+      <!--
+      If the container being copied has one or more
+      <filename>lxc.hook.clone</filename> specified, then the specified hooks
+      will be called for the new container. The first 3 arguments passed to the
+      clone hook will be the container name, a section ('lxc'), and the hook
+      type ('clone'). Extra arguments passed to <command>lxc-copy</command> will
+      be passed to the hook program starting at argument 4. The
+      <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
+      the path under which the container's root filesystem is mounted. The
+      configuration file pathname is stored in
+      <filename>LXC_CONFIG_FILE</filename>, the new container name in
+      <filename>LXC_NAME</filename>, the old container name in
+      <filename>LXC_SRC_NAME</filename>, and the path or device on which the
+      rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
+      -->
+      コピーされるコンテナに 1 つ以上の <filename>lxc.hook.clone</filename> の指定が存在する場合、指定されたフックは新しいコンテナに対して呼ばれます。
+      クローンフックに渡される最初の 3 つの引数は、コンテナ名、セクション ('lxc')、フックタイプ ('clone') となります。
+      <command>lxc-copy</command> に渡される追加の引数は、フックプログラムに渡される引数の 4 番目以降となります。
+      <filename>LXC_ROOTFS_MOUNT</filename> 環境変数には、コンテナの root ファイルシステムがマウントされるパスが与えられます。
+      設定ファイルのパス名は <filename>LXC_CONFIG_FILE</filename> に、新しいコンテナ名は <filename>LXC_NAME</filename>、古いコンテナ名は <filename>LXC_SRC_NAME</filename> に、rootfs のあるパスまたはデバイスは <filename>LXC_ROOTFS_PATH</filename> に保存されます。
+    </para>
+  </refsect1>
+
+  &commonoptions;
+
+  &seealso;
+
+  <refsect1>
+    <title>Author</title>
+    <para>Christian Brauner <email>christian.brauner@mailbox.org</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
index f8b6064..3991976 100644 (file)
@@ -112,7 +112,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-f <replaceable>config_file</replaceable></option>
+         <option>-f, --config <replaceable>config_file</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -127,7 +127,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-t <replaceable>template</replaceable></option>
+         <option>-t, --template <replaceable>template</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -151,12 +151,12 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-B <replaceable>backingstore</replaceable></option>
+         <option>-B, --bdev <replaceable>backingstore</replaceable></option>
        </term>
        <listitem>
           <para>
             <!--
-           'backingstore' is one of 'dir', 'lvm', 'loop', 'btrfs', 'zfs', or 'best'.  The
+           'backingstore' is one of 'dir', 'lvm', 'loop', 'btrfs', 'zfs', 'rbd', or 'best'.  The
            default is 'dir', meaning that the container root filesystem
            will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
            This backing store type allows the optional
@@ -184,7 +184,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            <replaceable>&#045;&#045;fssize SIZE</replaceable> will create a LV (and
            filesystem) of size SIZE rather than the default, which is 1G.
             -->
-            'backingstore' には 'dir' か 'lvm' か 'loop' か 'btrfs' か 'zfs' か 'best' のいずれかを指定します。
+            'backingstore' には 'dir', 'lvm', 'loop', 'btrfs', 'zfs', 'rbd', 'best' のいずれかを指定します。
             デフォルトは 'dir' で、コンテナのルートファイルシステムが <filename>@LXCPATH@/container/rootfs</filename> 以下のディレクトリであることを意味します。
             'dir' にはオプションとして <replaceable>--dir ROOTFS</replaceable> を指定することも可能です。
             このオプションは、デフォルトの代わりに特定のパス以下にコンテナの rootfs を置くということになります。
@@ -206,6 +206,17 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            backingstore が 'loop' の場合、'lvm' と同様に <replaceable>--fstype FSTYPE</replaceable> と <replaceable>--fssize SIZE</replaceable> が使えます。これらの値のデフォルト値は 'lvm' の場合と同じです。
          </para>
          <para>
+                <!--
+                If backingstore is 'rbd', then you will need to have a valid configuration in <filename>ceph.conf</filename> and a <filename>ceph.client.admin.keyring</filename> defined.
+                You can specify the following options :
+                <replaceable>&#045;&#045;rbdname RBDNAME</replaceable> will create a blockdevice named RBDNAME rather than the default, which is the container name.
+                <replaceable>&#045;&#045;rbdpool POOL</replaceable> will create the blockdevice in the pool named POOL, rather than the default, which is 'lxc'.
+                -->
+                backingstore が 'rbd' の場合、<filename>ceph.conf</filename> に有効な設定がされており、<filename>ceph.client.admin.keyring</filename> が定義されている必要があります。
+                <replaceable>--rbdname RBDNAME</replaceable> を指定すると、RBDNAME という名前のブロックデバイスを作成します。このオプションを指定しない場合のデフォルトのブロックデバイス名はコンテナ名です。
+                <replaceable>--rbdpool POOL</replaceable> を指定すると、POOL という名前のプール内にブロックデバイスを作成します。このオプションを指定しない場合のデフォルトのプール名は 'lxc' です。
+         </para>
+         <para>
             <!--
            If backingstore is 'best', then lxc will try, in order, btrfs,
            zfs, lvm, and finally a directory backing store.
index 4a79397..24fba0a 100644 (file)
@@ -48,7 +48,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <!--
       destroy a container.
       -->
-      コンテナの破壊
+      コンテナの削除
     </refpurpose>
   </refnamediv>
 
@@ -57,6 +57,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <command>lxc-destroy</command>
       <arg choice="req">-n <replaceable>name</replaceable></arg>
       <arg choice="opt">-f</arg>
+      <arg choice="opt">-s</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -94,6 +95,19 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
          </para>
        </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><option>-s, --snapshots</option></term>
+        <listitem>
+         <para>
+            <!--
+            destroy the specified container including all its snapshots.
+            -->
+            指定したコンテナとそのスナップショットをすべて削除します。
+         </para>
+        </listitem>
+      </varlistentry>
+
     </variablelist>
 
   </refsect1>
@@ -115,7 +129,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            destroyed.You can use the <command>lxc-ls</command>
            command to list the available containers on the system.
             -->
-            削除するために指定したコンテナが見つかりません。
+            削除する対象のコンテナが見つかりません。
             おそらくそのコンテナが存在しないのか、既に削除された後なのでしょう。
             <command>lxc-ls</command> コマンドを使って、システム上に存在するコンテナのリストを得ることができます。
           </para>
index b7ce115..cb637e1 100644 (file)
@@ -76,7 +76,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     <variablelist>
       <varlistentry>
         <term>
-          <option><optional>-h</optional></option>
+          <option>-h</option>
         </term>
         <listitem>
           <para>
@@ -89,9 +89,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       </varlistentry>
 
       <varlistentry>
-        <term>
-          <option>-n</option>
-        </term>
+        <term><option>-n, --name=<replaceable>NAME</replaceable></option></term>
         <listitem>
           <para>
             <!--
index 8df1928..eb27c5e 100644 (file)
@@ -80,13 +80,13 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-c <replaceable>KEY</replaceable></optional></option>
+          <option>-c, --config <replaceable>KEY</replaceable></option>
         </term>
         <listitem>
           <para>
             <!--
             Print a configuration key from the container. This option
-            may be given mulitple times to print out multiple key = value pairs.
+            may be given multiple times to print out multiple key = value pairs.
             -->
             コンテナの設定値を表示します。このオプションは複数の key = value のペアを表示したい場合には複数回指定することも可能です。
           </para>
@@ -95,7 +95,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-s</optional></option>
+          <option>-s, --state</option>
         </term>
         <listitem>
           <para>
@@ -109,7 +109,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-p</optional></option>
+          <option>-p, --pid</option>
         </term>
         <listitem>
           <para>
@@ -123,21 +123,21 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-i</optional></option>
+          <option>-i, --ips</option>
         </term>
         <listitem>
           <para>
             <!--
             Just print the container's IP addresses.
             -->
-            コンテナの IP アドレスを表示します。
+            コンテナの IP アドレスを表示します。
           </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term>
-          <option><optional>-S</optional></option>
+          <option>-S, --stats</option>
         </term>
         <listitem>
           <para>
@@ -174,7 +174,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-H</optional></option>
+          <option>-H, --no-humanize</option>
         </term>
         <listitem>
           <para>
index 5860783..a3c0c61 100644 (file)
@@ -28,6 +28,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
 <!DOCTYPE refentry PUBLIC @docdtd@ [
 
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
 <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
 ]>
 
@@ -55,7 +56,6 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     <cmdsynopsis>
       <command>lxc-ls</command>
       <arg choice="opt">-1</arg>
-      <arg choice="opt">-P <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">--active</arg>
       <arg choice="opt">--frozen</arg>
       <arg choice="opt">--running</arg>
@@ -63,9 +63,8 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <arg choice="opt">-f</arg>
       <arg choice="opt">-F <replaceable>format</replaceable></arg>
       <arg choice="opt">-g <replaceable>groups</replaceable></arg>
-      <arg choice="opt">--nesting</arg>
-      <arg choice="opt">filter</arg>
-      <arg choice="opt">--version</arg>
+      <arg choice="opt">--nesting=<replaceable>NUM</replaceable></arg>
+      <arg choice="opt">--filter=<replaceable>regex</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -85,7 +84,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     <variablelist>
       <varlistentry>
         <term>
-          <option><optional>-1</optional></option>
+          <option>-1</option>
         </term>
         <listitem>
           <para>
@@ -98,22 +97,8 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       </varlistentry>
 
       <varlistentry>
-        <term>
-          <option><optional>-P, --lxcpath</optional></option>
-        </term>
-        <listitem>
-          <para>
-            <!--
-            Use an alternate container path. The default is @LXCPATH@.
-            -->
-            デフォルトと別のコンテナパスを使用します。デフォルトは @LXCPATH@ です。
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>
-         <option><optional>--active</optional></option>
+         <option>--active</option>
        </term>
        <listitem>
          <para>
@@ -127,7 +112,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--frozen</optional></option>
+          <option>--frozen</option>
         </term>
         <listitem>
           <para>
@@ -141,7 +126,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--running</optional></option>
+          <option>--running</option>
         </term>
         <listitem>
           <para>
@@ -155,7 +140,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--stopped</optional></option>
+          <option>--stopped</option>
         </term>
         <listitem>
           <para>
@@ -169,7 +154,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-f, --fancy</optional></option>
+          <option>-f,--fancy</option>
         </term>
         <listitem>
           <para>
@@ -183,7 +168,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-F, --fancy-format <replaceable>format</replaceable></optional></option>
+          <option>-F,--fancy-format <replaceable>format</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -198,7 +183,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-g, --groups <replaceable>groups</replaceable></optional></option>
+          <option>-g,--groups <replaceable>groups</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -213,44 +198,32 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--nesting</optional></option>
+          <option>--nesting=<replaceable>NUM</replaceable></option>
         </term>
         <listitem>
           <para>
             <!--
-            Show nested containers.
+            Show nested containers. The number of nesting levels to be shown can
+            be specified by passing a number as argument.
             -->
-            ã\83\8dã\82¹ã\83\88ã\81\95ã\82\8cã\81\9fã\82³ã\83³ã\83\86ã\83\8aã\82\92表示ã\81\97ます。
+            ã\83\8dã\82¹ã\83\88ã\81\97ã\81\9fã\82³ã\83³ã\83\86ã\83\8aã\82\92表示ã\81\97ã\81¾ã\81\99ã\80\82å¼\95æ\95°ã\81¨ã\81\97ã\81¦æ\95°å­\97ã\82\92æ\8c\87å®\9aã\81\99ã\82\8bã\81\93ã\81¨ã\81§ã\80\81表示ã\81\99ã\82\8bã\83\8dã\82¹ã\83\88ã\81®ã\83¬ã\83\99ã\83«ã\82\92æ\8c\87å®\9aã\81§ã\81\8dます。
           </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term>
-          <option><optional>filter</optional></option>
+          <option>--filter=<replaceable>regex</replaceable></option>
         </term>
         <listitem>
           <para>
-            <!--
-            The filter passed to <command>lxc-ls</command> will be
-            applied to the container name. The format is a regular expression.
-            -->
-            コンテナ名に対して適用する <command>lxc-ls</command> に与えるフィルタ。
-            フォーマットは正規表現です。
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>
-          <option><optional>--version</optional></option>
-        </term>
-        <listitem>
-          <para>
-            <!--
-            Show the version number.
-            -->
-            バージョン番号を表示します。
+           <!--
+            The regular expression passed to <command>lxc-ls</command> will be
+            applied to the container name. The format is a POSIX extended
+            regular expression. It can also be given as additional argument
+            without explicitly using <option>&#045;&#045;filter</option>.
+           -->
+           <command>lxc-ls</command> に与える、コンテナ名に対して適用する正規表現です。フォーマットは POSIX 拡張正規表現です。<option>--filter</option> を明示的に使わずに、追加の引数として与えることもできます。
           </para>
         </listitem>
       </varlistentry>
@@ -290,11 +263,24 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     </variablelist>
   </refsect1>
 
+  &commonoptions;
+
   &seealso;
 
   <refsect1>
+    <title><!-- History -->履歴</title>
+    <!--
+    Written originally as a shell script by Daniel Lezcano and Serge Hallyn.
+    Later reimplemented and extended in Python by Stéphane Graber and then
+    reimplemented and extended in C by Christian Brauner.
+      -->
+    元は Daniel Lezcano と Serge Hallyn によりシェルスクリプトとして書かれていました。のちに、Stéphane Graber が Python で再実装し、拡張しました。その後、Christian Brauner が C で再実装し、拡張しました。
+  </refsect1>
+
+  <refsect1>
     <title><!-- Author -->作者</title>
-    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+    <para>Christian Brauner <email>christian.brauner@mailbox.org</email>,
+    Stéphane Graber <email>stgraber@ubuntu.com</email></para>
   </refsect1>
 
 </refentry>
index 673a806..49125d2 100644 (file)
@@ -72,7 +72,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <command>lxc-snapshot</command>
       <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
       <arg choice="req">-r, -restore <replaceable>snapshot-name</replaceable></arg>
-      <arg choice="opt"> <replaceable> newname</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable> newname</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -164,16 +164,14 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
          </varlistentry>
 
          <varlistentry>
-           <term> <option>newname</option> </term>
+           <term> <option>-N, --newname</option> </term>
           <listitem>
-           <para>
-              <!--
-                  When restoring a snapshot, the last optional argument is the name to use for the restored container.  If no name is given, then the original container will be destroyed and the restored container will take its place.  Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots.
-              -->
-              スナップショットをリストアする際、最後のオプション引数はリストアされたコンテナの名前として使用されます。
-              もし名前が与えられてない場合、元のコンテナが破壊され、リストアされるコンテナに置き換えられます。
-              スナップショット元を削除することは、aufs, overlayfs, zfs がバックエンドのスナップショットでは出来ないことに注意が必要です。
-            </para>
+            <para>
+             <!-- When restoring a snapshot, the last optional argument if not given explicitly Via <command>\-\-newname</command> is the name to use for the restored container.  If the newname is identical to the original name of the container, then the original container will be destroyed and the restored container will take its place. Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots. -->
+             スナップショットをリストアする際、<command>--newname</command> の値として明示的に指定しない場合でも、最後のオプション引数はリストアするコンテナの名前として使用します。
+             もし newname が元のコンテナの名前と同じ場合、元のコンテナが削除され、リストアされるコンテナに置き換えられます。
+             スナップショット元を削除することは、aufs, overlayfs, zfs がバックエンドのスナップショットではできないことに注意が必要です。
+           </para>
           </listitem>
          </varlistentry>
 
index 3f79c74..0124f48 100644 (file)
@@ -82,7 +82,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     <variablelist>
       <varlistentry>
         <term>
-          <option>-o</option>
+          <option>-o, --orig <replaceable>orig</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -96,7 +96,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-n</optional></option>
+          <option>-n, --name <replaceable>name</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -110,7 +110,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>-d</optional></option>
+          <option>-d, --daemon</option>
         </term>
         <listitem>
           <para>
@@ -126,7 +126,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--bdir</optional></option>
+          <option>-b, --bdir <replaceable>bdir</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -142,7 +142,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--user</optional></option>
+          <option>-u, --user <replaceable>user</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -158,7 +158,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--key</optional></option>
+          <option>-S, --key <replaceable>key</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -172,7 +172,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--storage-type</optional></option>
+          <option>-s, --storage-type <replaceable>storage type</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -186,7 +186,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--union-type</optional></option>
+          <option>-U, --union-type <replaceable>union type</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -202,7 +202,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>--keep-data</optional></option>
+          <option>-k, --keep-data</option>
         </term>
         <listitem>
           <para>
@@ -218,7 +218,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
         <term>
-          <option><optional>COMMAND</optional></option>
+          <option>COMMAND</option>
         </term>
         <listitem>
           <para>
@@ -279,6 +279,17 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title><!-- Notes -->注意</title>
+    <para>
+      <!--
+    <command>lxc-start-ephemeral</command> is deprecated in favor of
+    <command>lxc-copy</command>.
+    -->
+      <command>lxc-start-ephemeral</command> は <command>lxc-copy</command> に置き換えられ、廃止される予定です。
+    </para>
+  </refsect1>
+
   &seealso;
 
   <refsect1>
index aed1947..79f7a9a 100644 (file)
@@ -77,11 +77,14 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       the container's init process, waiting up to 60 seconds for the container
       to exit, and then returning. If the container fails to cleanly exit in
       60 seconds, it will be sent the <command>lxc.stopsignal</command>
-      (defaults to SIGKILL) to force it to shut down.
+      (defaults to SIGKILL) to force it to shut down. A request to reboot will
+      send the <command>lxc.rebootsignal</command> (defaults to SIGINT) to the
+      container's init process.
       -->
       <command>lxc-stop</command> は、リブート、クリーンシャットダウン、コンテナ内の全てのプロセスの kill のどれかを行います。
       デフォルトでは、コンテナのクリーンなシャットダウンを <command>lxc.haltsignal</command> (デフォルトでは SIGPWR) をコンテナの init プロセスに送ることでリクエストし、コンテナの終了を 60 秒待ち、return します。
-      コンテナが 60 秒の間にクリーンに終了するのに失敗した場合、<command>lxc.stopsignal</command> (デフォルトでは SIGKILL) を送り、強制的にシャットダウンします。
+      コンテナが 60 秒の間にクリーンに終了するのに失敗した場合、<command>lxc.stopsignal</command> (デフォルトは SIGKILL です) を送り、強制的にシャットダウンします。
+      リブートのリクエストは <command>lxc.rebootsignal</command> に設定されたシグナルをコンテナの init プロセスに送ります (デフォルトは SIGINT です)。
     </para>
 
     <para>
index c134b3a..66a79b4 100644 (file)
@@ -79,7 +79,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-d, --delay <replaceable>delay</replaceable></optional></option>
+          <option>-d, --delay <replaceable>delay</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -93,7 +93,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
       <varlistentry>
         <term>
-          <option><optional>-s, --sort <replaceable>sortby</replaceable></optional></option>
+          <option>-s, --sort <replaceable>sortby</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -110,7 +110,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
       <varlistentry>
         <term>
-          <option><optional>-r, --reverse</optional></option>
+          <option>-r, --reverse</option>
         </term>
         <listitem>
           <para>
index 815dd6c..ce21a17 100644 (file)
@@ -106,13 +106,17 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
            <replaceable>NETWORK</replaceable>. This allows one to change
            the context of the process to e.g. the network namespace of the
            container while retaining the other namespaces as those of the
-           host.
+            host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
             -->
             アタッチする名前空間を、パイプでつなげたリストで指定します。
             例えば <replaceable>NETWORK|IPC</replaceable> のようにです。
             指定できる値は <replaceable>MOUNT</replaceable>、<replaceable>PID</replaceable>、<replaceable>UTSNAME</replaceable>、<replaceable>IPC</replaceable>、<replaceable>USER </replaceable>、<replaceable>NETWORK</replaceable> です。
             これにより、プロセスのコンテキストを変更することができます。
             例えば、コンテナのネットワーク名前空間だけを変更し、他の名前空間をホストのものと同じものに保ったままにするというようなことです。
+            (パイプ記号を <replaceable>MOUNT\|PID</replaceable> のようにエスケー
+プするか、<replaceable>"MOUNT|PID"</replaceable> のように引用符号を付ける必要が>あります。)
          </para>
        </listitem>
       </varlistentry>
index 9d568be..4a9c055 100644 (file)
@@ -75,6 +75,10 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <para>
       <command>user</command> <command>type</command> <command>bridge</command> <command>number</command>
       </para>
+      <para>もしくは</para>
+      <para>
+      <command>@group</command> <command>type</command> <command>bridge</command> <command>number</command>
+      </para>
       <para>
         <!--
       Where
@@ -100,6 +104,20 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
        <varlistentry>
          <term>
+           <option>@group</option>
+         </term>
+         <listitem>
+           <para>
+             <!--
+             is the groupname to which this entry applies.
+               -->
+             このエントリを適用するグループ名
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
            <option>type</option>
          </term>
          <listitem>
@@ -136,15 +154,30 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
          <listitem>
            <para>
               <!--
-             is the number of network interfaces of the given type which the
-             given user may attach to the given bridge, for instance <filename>2</filename>.
+             is the number or quota of network interfaces of the given type which the
+             given user or group may attach to the given bridge, for instance <filename>2</filename>.
               -->
-              指定したユーザが、指定したブリッジに接続できる、指定した形式のネットワークインターフェースの数。
+              æ\8c\87å®\9aã\81\97ã\81\9fã\83¦ã\83¼ã\82¶ã\82\82ã\81\97ã\81\8fã\81¯ã\82°ã\83«ã\83¼ã\83\97ã\81\8cã\80\81æ\8c\87å®\9aã\81\97ã\81\9fã\83\96ã\83ªã\83\83ã\82¸ã\81«æ\8e¥ç¶\9aã\81§ã\81\8dã\82\8bã\80\81æ\8c\87å®\9aã\81\97ã\81\9få½¢å¼\8fã\81®ã\83\8dã\83\83ã\83\88ã\83¯ã\83¼ã\82¯ã\82¤ã\83³ã\82¿ã\83¼ã\83\95ã\82§ã\83¼ã\82¹ã\81®æ\95°ã\80\82
               例えば <filename>2</filename> のように指定します。
             </para>
          </listitem>
        </varlistentry>
       </variablelist>
+
+      <para>
+        <!--
+        Since a user can be specified both by username as well as one or
+        more usergroups, it is possible that several configuration lines
+        enable that user to create network interfaces. In such cases, any
+        interfaces create are counted towards the quotas of the user or group
+        in the order in which they appear in the file. If the quota of one
+        line is full, the rest will be parsed until one is found or the end of
+        the file.
+          -->
+       あるユーザに対する指定が、ユーザ名とひとつ以上のユーザグループの両方で指定される可能性があるので、そのユーザがネットワークインターフェースを作れるようにする設定が複数行にわたる可能性があります。
+        このような場合、あるインターフェースの作成は、設定ファイルに現れた順にユーザもしくはグループの割り当てをカウントします。
+        もしある行の設定に対する割り当てが一杯の場合、他の割り当て行が現れるかファイルの最後に達するまで、残りの行を読み込んでチェックします。
+      </para>
     </refsect2>
 
   </refsect1>
index e51d964..e60493c 100644 (file)
@@ -78,7 +78,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-s <replaceable>states</replaceable></option>
+         <option>-s, --state <replaceable>states</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -94,7 +94,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
 
       <varlistentry>
        <term>
-         <option>-t <replaceable>timeout</replaceable></option>
+         <option>-t, --timeout <replaceable>timeout</replaceable></option>
        </term>
        <listitem>
          <para>
index 98b8f4d..f5b8afa 100644 (file)
@@ -91,10 +91,13 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <!--
       Each option in the configuration file has the form <command>key
       = value</command> fitting in one line. The '#' character means
-      the line is a comment.
+      the line is a comment. List options, like capabilities and cgroups
+      options, can be used with no value to clear any previously
+      defined values of that option.
       -->
       設定ファイルのオプション一つを、<command>key = value</command> の形で一行で表します。
       '#' は、その行はコメントであることを示します。
+      ケーパビリティや cgroup のオプションのような、リスト形式で指定するオプションでは、value がない形式で指定できます。このように使うと、それ以前に定義した値をすべてクリアします。
     </para>
 
     <refsect2>
@@ -213,32 +216,62 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <title><!-- Halt signal -->クリーンなシャットダウン時のシグナル</title>
       <para>
         <!--
-    Allows one to specify signal name or number, sent by lxc-stop to the
-    container's init process to cleanly shutdown the container. Different
-    init systems could use different signals to perform clean shutdown
-    sequence. This option allows the signal to be specified in kill(1)
-    fashion, e.g. SIGPWR, SIGRTMIN+14, SIGRTMAX-10 or plain number. The
-    default signal is SIGPWR.
+        Allows one to specify signal name or number, sent by lxc-stop to the
+        container's init process to cleanly shutdown the container. Different
+        init systems could use different signals to perform clean shutdown
+        sequence. This option allows the signal to be specified in kill(1)
+        fashion, e.g. SIGPWR, SIGRTMIN+14, SIGRTMAX-10 or plain number. The
+        default signal is SIGPWR.
           -->
-        lxc-stop ã\81\8cã\82³ã\83³ã\83\86ã\83\8aã\82\92ã\82¯ã\83ªã\83¼ã\83³ã\81«ã\82·ã\83£ã\83\83ã\83\88ã\83\80ã\82¦ã\83³ã\81\99ã\82\8bã\81\9fã\82\81ã\81«ã\82³ã\83³ã\83\86ã\83\8aã\81® init ã\83\97ã\83­ã\82»ã\82¹ã\81«é\80\81ã\82\8bã\82·ã\82°ã\83\8aã\83«å\90\8dã\81\8bç\95ªå\8f·ã\82\92æ\8c\87å®\9aã\81\99ã\82\8bã\81\93ã\81¨ã\81\8cã\81§ã\81\8dã\81¾ã\81\99ã\80\82
+        lxc-stop がコンテナをクリーンにシャットダウンするためにコンテナの init プロセスに送るシグナル名か番号を指定できます。
         init システムによって、クリーンなシャットダウンを行うために使うシグナルは異なります。
         このオプションではシグナルとして kill(1) で使う形式を指定することができます。
         例えば SIGKILL, SIGRTMIN+14, SIGRTMAX-10 のような形式、もしくは数字を指定します。デフォルトのシグナルは SIGPWR です。
       </para>
       <variablelist>
-    <varlistentry>
-      <term>
-        <option>lxc.haltsignal</option>
-      </term>
-      <listitem>
-        <para>
-          <!--
-          specify the signal used to halt the container
+        <varlistentry>
+          <term>
+            <option>lxc.haltsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              specify the signal used to halt the container
+              -->
+              コンテナをシャットダウンするために使うシグナルを指定します。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>リブート時のシグナル <!-- Reboot signal --></title>
+      <para>
+        <!--
+        Allows one to specify signal name or number, sent by lxc-stop to
+        reboot the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGTERM, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGINT.
           -->
-          コンテナをシャットダウンするのに使うシグナルを指定します
-        </para>
-      </listitem>
-    </varlistentry>
+        lxc-stop がコンテナをリブートするために送るシグナル名か番号を指定できます。
+        このオプションではシグナルとして kill(1) で使う形式を指定することができます。
+        例えば SIGKILL, SIGRTMIN+14, SIGRTMAX-10 のような形式、もしくは数字を指定します。デフォルトのシグナルは SIGINT です。
+          </para>
+          <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.rebootsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              specify the signal used to reboot the container
+                -->
+              コンテナをリブートするために使うシグナルを指定します。
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -246,29 +279,29 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <title><!-- Stop signal -->強制停止時のシグナル</title>
       <para>
         <!--
-    Allows one to specify signal name or number, sent by lxc-stop to forcibly
-    shutdown the container. This option allows signal to be specified in
-    kill(1) fashion, e.g. SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
-    The default signal is SIGKILL.
-    -->
+        Allows one to specify signal name or number, sent by lxc-stop to forcibly
+        shutdown the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGKILL.
+          -->
         lxc-stop がコンテナを強制的にシャットダウンするために送るシグナル名か番号を指定することができます。
         このオプションではシグナルとして kill(1) で使う形式を指定することができます。
         例えば SIGKILL, SIGRTMIN+14, SIGRTMAX-10 のような形式、もしくは数字を指定します。デフォルトのシグナルは SIGKILL です。
       </para>
       <variablelist>
-    <varlistentry>
-      <term>
-        <option>lxc.stopsignal</option>
-      </term>
-      <listitem>
-        <para>
-          <!--
-          specify the signal used to stop the container
-          -->
-          コンテナを停止するのに使用するシグナルを指定します。
-        </para>
-      </listitem>
-    </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.stopsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+                  specify the signal used to stop the container
+                -->
+              コンテナを停止するのに使用するシグナルを指定します。
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -304,6 +337,80 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     </refsect2>
 
     <refsect2>
+      <title><!-- Init ID -->Init が使う ID</title>
+      <para>
+        <!--
+        Sets the UID/GID to use for the init system, and subsequent command, executed by lxc-execute.
+        -->
+        lxc-execute が実行するコンテナの init と、その後に起動するコマンドが使用する UID/GID を設定します。
+
+        <!--
+        These options are only used when lxc-execute is started in a private user namespace.
+        -->
+        このオプションは lxc-execute がユーザ名前空間内で起動するときのみ使われます。
+
+        <!--
+        Defaults to: UID(0), GID(0)
+        -->
+        デフォルト値は UID(0), GID(0) です。
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.init_uid</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              UID to use within a private user namesapce for init.
+                -->
+              ユーザ名前空間内で init が使う UID です。
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.init_gid</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              GID to use within a private user namesapce for init.
+                -->
+              ユーザ名前空間内で init が使う GID です。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Ephemeral -->一時的なコンテナ</title>
+      <para>
+        <!--
+        Allows one to specify whether a container will be destroyed on shutdown.
+          -->
+        シャットダウン後にコンテナを削除するかどうかを指定できます。
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.ephemeral</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              The only allowed values are 0 and 1. Set this to 1 to destroy a
+              container on shutdown. 
+                -->
+              指定できる値は 0 または 1 のみです。この値を 1 に設定すると、シャットダウン後にコンテナを削除します。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
       <title><!-- Network -->ネットワーク</title>
       <para>
         <!--
@@ -322,6 +429,19 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
         そして、仮に物理ネットワークインターフェースが一つしかなくても、コンテナ内でいくつもの仮想インターフェースを使うことができます。
       </para>
       <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.network</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              may be used without a value to clear all previous network options.
+              -->
+              値を指定せずに使い、それ以前に定義されたすべてのネットワークオプションをクリアできます。
+            </para>
+          </listitem>
+        </varlistentry>
        <varlistentry>
          <term>
            <option>lxc.network.type</option>
@@ -416,16 +536,18 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
              <option>lxc.network.macvlan.mode</option> specifies the
              mode the macvlan will use to communicate between
              different macvlan on the same upper device. The accepted
-             modes are <option>private</option>, the device never
-             communicates with any other device on the same upper_dev (default),
-             <option>vepa</option>, the new Virtual Ethernet Port
+              modes are <option>private</option>, <option>vepa</option>,
+              <option>bridge</option> and <option>passthru</option>.
+             In <option>private</option> mode, the device never
+              communicates with any other device on the same upper_dev (default).
+              In <option>vepa</option> mode, the new Virtual Ethernet Port
              Aggregator (VEPA) mode, it assumes that the adjacent
              bridge returns all frames where both source and
              destination are local to the macvlan port, i.e. the
              bridge is set up as a reflective relay.  Broadcast
              frames coming in from the upper_dev get flooded to all
              macvlan interfaces in VEPA mode, local frames are not
-             delivered locally, or <option>bridge</option>, it
+              delivered locally. In <option>bridge</option> mode, it
              provides the behavior of a simple bridge between
              different macvlan interfaces on the same port. Frames
              from one interface to another one get delivered directly
@@ -434,20 +556,26 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
              interface, but when they come back from a reflective
              relay, we don't deliver them again.  Since we know all
              the MAC addresses, the macvlan bridge mode does not
-             require learning or STP like the bridge module does.
+              require learning or STP like the bridge module does. In
+              <option>passthru</option> mode, all frames received by
+              the physical interface are forwarded to the macvlan
+              interface. Only one macvlan interface in <option>passthru</option>
+              mode is possible for one physical interface.
               -->
               <option>macvlan:</option> macvlan インターフェースは <option>lxc.network.link</option> により指定されるインターフェースとリンクし、コンテナに割り当てられます。
               <option>lxc.network.macvlan.mode</option> でモードを指定すると、その macvlan の指定を、同じ上位デバイスで異なる macvlan の間の通信をする時に使います。
-              受け入れられたモードが <option>private</option> であれば、デバイスは同じ上位デバイスの他のデバイスとの通信を行いません (デフォルト)。
-              新しい仮想イーサネットポート集約モード (Virtual Ethernet Port Aggregator (VEPA)) である <option>vepa</option> は、隣接したポートが、ソースとデスティネーションの両方が macvlan ポートに対してローカルであるフレームを全て返すと仮定します。
+              指定できるモードは <option>private</option>、<option>vepa</option>、<option>bridge</option>、<option>passthru</option> のいずれかです。
+              <option>private</option> モードの場合、デバイスは同じ上位デバイスの他のデバイスとの通信を行いません (デフォルト)。
+              新しい仮想イーサネットポート集約モード (Virtual Ethernet Port Aggregator (VEPA)) である <option>vepa</option> モードの場合、隣接したポートが、ソースとデスティネーションの両方が macvlan ポートに対してローカルであるフレームを全て返すと仮定します。
               すなわち、ブリッジが reflective relay として設定されているということです。
               上位デバイスから入ってくるブロードキャストフレームは、VEPA モードである全ての macvlan インターフェースに送りつけられます。
               ローカルのフレームはローカルには配送されません。
-              <option>bridge</option> ã\81®æ\8c\87å®\9aã\81¯、同じポートの異なる macvlan インターフェースの間のシンプルなブリッジとして動作します。
+              <option>bridge</option> ã\83¢ã\83¼ã\83\89ã\81®å ´å\90\88、同じポートの異なる macvlan インターフェースの間のシンプルなブリッジとして動作します。
               あるインターフェースから他のインターフェースへのフレームは、直接配送され、外部には送出されません。
               ブロードキャストフレームは、全ての他のブリッジと外部のインターフェースに対して送られます。
               しかし、reflective relay からフレームが返ってきたときは、再度それを配送することはしません。
               全ての MAC アドレスを知っているので、ブリッジモジュールのように、macvlan ブリッジモードは学習や STP の必要はありません。
+              <option>passthru</option> モードの場合、物理インターフェースで受け取った全てのフレームは macvlan インターフェースに転送されます。<option>passthru</option> モードの場合、ひとつの macvlan インターフェースだけが、ひとつの物理インターフェースに対して設定できます。
            </para>
 
            <para>
@@ -895,7 +1023,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
        <filename>/dev</filename> to be set up as needed in the container
        rootfs.  If lxc.autodev is set to 1, then after mounting the container's
        rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
-       (limited to 100k) and fill in a minimal set of initial devices.
+       (limited to 500k) and fill in a minimal set of initial devices.
         This is generally required when starting a container containing
         a "systemd" based "init" but may be optional at other times.  Additional
         devices in the containers /dev directory may be created through the
@@ -903,7 +1031,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
         -->
         デフォルトでは、lxc はコンテナの <filename>/dev</filename> 以下に fd, stdin, stdout, stderr のシンボリックリンクを作成しますが、自動的にはデバイスノードのエントリは作成しません。
         これは、コンテナの rootfs で必要な設定を行えるようにするものです。
-        lxc.autodev が 1 に設定されている場合、コンテナの rootfs をマウントした後、LXC は新しい tmpfs を <filename>/dev</filename> 以下にマウントします (100k 制限の)。
+        lxc.autodev が 1 に設定されている場合、コンテナの rootfs をマウントした後、LXC は新しい tmpfs を <filename>/dev</filename> 以下にマウントします (500k 制限の)。
         そして初期デバイスの最小限のセットを作成します。
         これは、"systemd" ベースの "init" 環境のコンテナを起動する時に通常必要ですが、他の環境の場合はオプショナルなものです。
         コンテナの /dev ディレクトリ内の追加デバイスは <option>lxc.hook.autodev</option> フックを使用して作成されます。
@@ -965,6 +1093,23 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
         これらのマウントポイントは、コンテナだけに見え、コンテナ外で実行されるプロセスから見えることはありません。
         例えば、/etc や /var や /home をマウントするときに役に立つでしょう。
       </para>
+      <para>
+       <!--
+       NOTE - LXC will generally ensure that mount targets and relative
+       bind-mount sources are properly confined under the container
+       root, to avoid attacks involving over-mounting host directories
+       and files.  (Symbolic links in absolute mount sources are ignored)
+       However, if the container configuration first mounts a directory which
+       is under the control of the container user, such as /home/joe, into
+        the container at some <filename>path</filename>, and then mounts
+        under <filename>path</filename>, then a TOCTTOU attack would be
+        possible where the container user modifies a symbolic link under
+        his home directory at just the right time.
+         -->
+       注意: 通常 LXC は、マウント対象と相対パス指定のバインドマウントを、適切にコンテナルート以下に閉じ込めます。
+       これは、ホストのディレクトリやファイルに対して重ね合わせを行うようなマウントによる攻撃を防ぎます。(絶対パス指定のマウントソース中の各パスがシンボリックリンクである場合は無視されます。)
+       しかし、もしコンテナの設定が最初に、/home/joe のようなコンテナユーザのコントロール配下にあるディレクトリを、コンテナ中のある <filename>path</filename> にマウントし、その後 <filename>path</filename> 以下でマウントが行われるような場合、コンテナユーザがタイミングを見計らって自身のホームディレクトリ以下でシンボリックリンクを操作するような TOCTTOU 攻撃が成立する可能性があります。
+      </para>
       <variablelist>
        <varlistentry>
          <term>
@@ -1256,6 +1401,15 @@ proc proc proc nodev,noexec,nosuid 0 0
                </para>
              </listitem>
            </itemizedlist>
+            <para>
+             <!--
+             If cgroup namespaces are enabled, then any <option>cgroup</option>
+             auto-mounting request will be ignored, since the container can
+             mount the filesystems itself, and automounting can confuse the
+             container init.
+               -->
+             cgroup 名前空間が有効の場合、<option>cgroup</option> の自動マウントの指定はどれも無視されます。これは、コンテナが自身でファイルシステムをマウントするため、自動マウントがコンテナの init を混乱させる可能性があるためです。
+            </para>
            <para>
               <!--
              Note that if automatic mounting of the cgroup filesystem
@@ -1338,14 +1492,16 @@ proc proc proc nodev,noexec,nosuid 0 0
           specifies that the rootfs should be an overlay with <filename>/upper</filename>
           being mounted read-write over a read-only mount of <filename>/lower</filename>.
           <filename>aufs:/lower:/upper</filename> does the same using aufs in place
-          of overlayfs. <filename>loop:/file</filename> tells lxc to attach
+          of overlayfs. For both <filename>overlayfs</filename> and
+          <filename>aufs</filename> multiple <filename>/lower</filename>
+          directories can be specified. <filename>loop:/file</filename> tells lxc to attach
           <filename>/file</filename> to a loop device and mount the loop device.
           -->
               ディレクトリ、単純なブロックデバイスのバックエンドを持つコンテナの場合、パス名を使うことができます。
               もし rootfs が nbd デバイスの場合、<filename>nbd:file:1</filename> という指定は <filename>file</filename> を nbd デバイスとして使用し、その 1 番目のパーティションが rootfs としてマウントされます。
               <filename>nbd:file</filename> という指定は、nbd デバイス自身をマウントします。
               <filename>overlayfs:/lower:/upper</filename> という指定は、rootfs は <filename>/lower</filename> という読み込み専用でマウントされるディレクトリの上に、<filename>/upper</filename> というディレクトリを読み書き可能で重ね合わせてマウントします。
-              <filename>aufs:/lower:/upper</filename> は overlayfs で指定している部分を aufs と指定すれば同じことになります。
+              <filename>aufs:/lower:/upper</filename> は overlayfs で指定している部分を aufs と指定すれば同じことになります。<filename>overlayfs</filename> と <filename>aufs</filename> は両方とも、複数の <filename>/lower</filename> ディレクトリを指定できます。
               <filename>loop:/file</filename> は <filename>/file</filename> を loop デバイスとして使用し、loop デバイスをマウントします。
            </para>
          </listitem>
@@ -1392,6 +1548,24 @@ proc proc proc nodev,noexec,nosuid 0 0
          </listitem>
        </varlistentry>
 
+        <varlistentry>
+          <term>
+            <option>lxc.rootfs.backend</option>
+          </term>
+          <listitem>
+            <para>
+             <!--
+              specify the rootfs backend type to use, for instance 'dir' or
+             'zfs'.  While this can be guessed by lxc at container startup,
+             doing so takes time.  Specifying it here avoids extra
+             processing.
+               -->
+             使用するバックエンドのタイプを、例えば 'dir' や 'zfs' のように指定します。
+             コンテナ起動時に LXC が推測できますが、時間がかかります。これを指定すると、余分な処理を避けられます。
+            </para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
     </refsect2>
 
@@ -1463,6 +1637,8 @@ proc proc proc nodev,noexec,nosuid 0 0
                <refentrytitle><command>capabilities</command></refentrytitle>
                <manvolnum>7</manvolnum>
              </citerefentry>,
+              If used with no value, lxc will clear any drop capabilities
+              specified up to this point.
               -->
               コンテナ内で削除するケーパビリティ (capability) を指定します。
               一行でスペース区切りで複数のケーパビリティを指定することも可能です。
@@ -1473,6 +1649,7 @@ proc proc proc nodev,noexec,nosuid 0 0
                <refentrytitle><command>capabilities</command></refentrytitle>
                <manvolnum>7</manvolnum>
              </citerefentry>
+             この設定を、値を指定しない状態で使った場合、それ以前に指定された削除対象のケーパビリティの指定をすべてクリアします (lxc.cap.drop に何も指定しない状態になります)。
            </para>
          </listitem>
        </varlistentry>
@@ -1504,10 +1681,12 @@ proc proc proc nodev,noexec,nosuid 0 0
        If lxc was compiled and installed with apparmor support, and the host
        system has apparmor enabled, then the apparmor profile under which the
        container should be run can be specified in the container
-       configuration.  The default is <command>lxc-container-default</command>.
+        configuration.  The default is <command>lxc-container-default-cgns</command>
+       if the host kernel is cgroup namespace aware, or
+       <command>lxc-container-default</command> othewise.
         -->
         lxc が apparmor サポートでコンパイルされ、インストールされている場合で、ホストで apparmor が有効な場合、コンテナが従って動くべき apparmor プロファイルは、コンテナの設定で指定することが可能です。
-        デフォルトは <command>lxc-container-default</command> です。
+        デフォルトは、ホストのカーネルで cgroup 名前空間が使える場合は <command>lxc-container-default-cgns</command>です。使えない場合は <command>lxc-container-default</command> です。
       </para>
       <variablelist>
        <varlistentry>
@@ -1525,6 +1704,14 @@ proc proc proc nodev,noexec,nosuid 0 0
               コンテナが apparmor による制限を受けないように設定するには、以下のように設定します。
            </para>
              <programlisting>lxc.aa_profile = unconfined</programlisting>
+            <para>
+             <!--
+              If the apparmor profile should remain unchanged (i.e. if you
+             are nesting containers and are already confined), then use
+             -->
+             もし apparmor プロファイルが変更されないままでなくてはならない場合 (ネストしたコンテナである場合や、すでに confined されている場合) は以下のように設定します。
+            </para>
+              <programlisting>lxc.aa_profile = unchanged</programlisting>
          </listitem>
        </varlistentry>
        <varlistentry>
@@ -1721,9 +1908,12 @@ mknod errno 0
          <listitem><para> Container name. </para></listitem>
          <listitem><para> Section (always 'lxc'). </para></listitem>
          <listitem><para> The hook type (i.e. 'clone' or 'pre-mount'). </para></listitem>
-         <listitem><para> Additional arguments In the
+         <listitem><para> Additional arguments. In the
          case of the clone hook, any extra arguments passed to
-         lxc-clone will appear as further arguments to the hook. </para></listitem>
+          lxc-clone will appear as further arguments to the hook.
+          In the case of the stop hook, paths to filedescriptors
+          for each of the container's namespaces along with their types
+          are passed. </para></listitem>
        </itemizedlist>
        The following environment variables are set:
        <itemizedlist>
@@ -1739,7 +1929,7 @@ mknod errno 0
          <listitem><para>コンテナ名</para></listitem>
          <listitem><para>セクション (常に 'lxc')</para></listitem>
          <listitem><para>フックのタイプ ('clone' や 'pre-mount' など)</para></listitem>
-         <listitem><para>追加の引数。clone フックの場合、lxc-clone に渡される追加の引数は、フックへの引数として追加されます。</para></listitem>
+         <listitem><para>追加の引数。clone フックの場合、lxc-clone に渡される追加の引数は、フックへの引数として追加されます。stop フックの場合は、コンテナの名前空間のそれぞれに対するファイルディスクリプタへのパスが、名前空間名とともに渡されます。</para></listitem>
        </itemizedlist>
         以下の環境変数がセットされます。
        <itemizedlist>
@@ -1860,6 +2050,32 @@ mknod errno 0
        </varlistentry>
       </variablelist>
       <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.hook.stop</option>
+          </term>
+          <listitem>
+            <para>
+             <!--
+              A hook to be run in the host's namespace with references
+              to the container's namespaces after the container has been shut
+              down. For each namespace an extra argument is passed to the hook
+              containing the namespace's type and a filename that can be used to
+              obtain a file descriptor to the corresponding namespace, separated
+              by a colon. The type is the name as it would appear in the
+              <filename>/proc/PID/ns</filename> directory.
+              For instance for the mount namespace the argument usually looks
+              like <filename>mnt:/proc/PID/fd/12</filename>.
+             -->
+             コンテナのシャットダウン後、コンテナの名前空間への参照とともに、ホストの名前空間で実行されるフックです。
+             それぞれの名前空間に対応する追加の引数がフックに渡されます。その引数にはコロンで区切られた名前空間のタイプ名とファイル名が含まれており、ファイル名は名前空間に対するファイルディスクリプタを取得するのに使えます。
+             タイプ名は <filename>/proc/PID/ns</filename> ディレクトリ内のファイル名です。
+             例えば、マウント名前空間に対応する引数は通常は <filename>mnt:/proc/PID/fd/12</filename> のようになります。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
        <varlistentry>
          <term>
            <option>lxc.hook.post-stop</option>
@@ -1895,6 +2111,21 @@ mknod errno 0
          </listitem>
        </varlistentry>
       </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.hook.destroy</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              A hook to be run when the container is destroyed.
+                -->
+              コンテナを破壊する際に実行されるフックです。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
     </refsect2>
 
     <refsect2>
@@ -2015,11 +2246,62 @@ mknod errno 0
              [<option>lxc.rootfs</option>]
               -->
               rootfs.mount へマウントされるコンテナのルートへのホスト上のパスです。
+             [<option>lxc.rootfs</option>]
            </para>
          </listitem>
        </varlistentry>
       </variablelist>
-
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_SRC_NAME</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Only for the clone hook. Is set to the original container name.
+              -->
+              clone フックの場合のみ使われます。クローン元のコンテナ名が設定されます。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_TARGET</option>
+          </term>
+          <listitem>
+            <para>
+             <!--
+              Only for the stop hook. Is set to "stop" for a container
+              shutdown or "reboot" for a container reboot.
+             -->
+             stop フックの場合のみ使われます。コンテナのシャットダウンの場合は "stop"、リブートの場合は "reboot" が設定されます。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_CGNS_AWARE</option>
+          </term>
+          <listitem>
+            <para>
+         <!--
+         If unset, then this version of lxc is not aware of cgroup
+         namespaces.  If set, it will be set to 1, and lxc is aware
+         of cgroup namespaces.  Note this does not guarantee that
+         cgroup namespaces are enabled in the kernel.  This is used
+         by the lxcfs mount hook.
+         -->
+              この変数が設定されていない場合、お使いのバージョンの LXC は cgroup 名前空間を扱えません。設定されている場合、この値は 1 に設定されています。そして、cgroup 名前空間を扱えます。
+              この変数はカーネルで cgroup 名前空間が有効であることは保証しません。この変数は lxcfs のマウントフックが使います。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
     </refsect2>
 
     <refsect2>
@@ -2150,6 +2432,22 @@ mknod errno 0
         </varlistentry>
         <varlistentry>
           <term>
+            <option>lxc.monitor.unshare</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              If not zero the mount namespace will be unshared from the host
+              before initializing the container (before running any pre-start
+              hooks). This requires the CAP_SYS_ADMIN capability at startup.
+              Default is 0.
+                -->
+              この値が 0 でない場合、コンテナが初期化される前 (pre-start フックが実行される前) にマウント名前空間がホストから unshare されます。この機能を使う場合、スタート時に CAP_SYS_ADMIN ケーパビリティが必要です。デフォルト値は 0 です。
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
             <option>lxc.group</option>
           </term>
           <listitem>
index 0aa37f0..e41c1a7 100644 (file)
@@ -690,7 +690,7 @@ rootfs
       <para>
         <!--
        Here is an example on how the combination of these commands
-       allow to list all the containers and retrieve their state.
+       allows one to list all the containers and retrieve their state.
        <programlisting>
          for i in $(lxc-ls -1); do
            lxc-info -n $i
index 44d5cb8..d66a967 100644 (file)
@@ -41,6 +41,11 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       </citerefentry>,
 
       <citerefentry>
+       <refentrytitle><command>lxc-copy</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
        <refentrytitle><command>lxc-destroy</command></refentrytitle>
        <manvolnum>1</manvolnum>
       </citerefentry>,
diff --git a/doc/ko/FAQ.txt b/doc/ko/FAQ.txt
new file mode 100644 (file)
index 0000000..50238ff
--- /dev/null
@@ -0,0 +1,67 @@
+
+Troubleshooting:
+===============
+
+
+Error:
+------
+
+error while loading shared libraries reported after sudo make install
+and when trying to run lxc-execute.
+
+"lxc-execute -n foo -f /usr/local/etc/lxc/lxc-macvlan.conf /bin/bash"
+
+/usr/local/bin/lxc-execute: error while loading shared libraries:
+  liblxc-0.5.0.so: cannot open shared object file: No such file or
+  directory
+
+Answer:
+-------
+update the ld cache by running ldconfig.
+
+
+
+Error:
+------
+
+error when starting a container.
+
+"lxc-start Invalid argument"
+
+"lxc-execute -n foo -f /usr/local/etc/lxc/lxc-macvlan.conf /bin/bash"
+"[syserr] lxc_start:96: Invalid argument - failed to fork into a new
+namespace"
+
+Answer:
+-------
+
+read the lxc man page about kernel version prereq :) most probably
+your kernel is not configured to support the container options you
+want to use.
+
+
+Error:
+------
+
+On Ubuntu 8.10, if using the cvs source code rather than
+the provided tarball. Then make is failing with many errors
+similar to the line below:
+==========
+../../libtool: line 810: X--tag=CC: command not found
+==========
+
+Answer:
+-------
+
+This is related to a compatibility problem between the shipped
+config/ltmain.sh and the libtool version installed on your
+Ubuntu 8.10 machine.
+You have to replace the config/ltmain.sh from cvs head by the one
+from your libtool package, make some cleaning and reissue all
+the build process:
+==========
+cd <your_lxc_working_dir>
+cp -f /usr/share/libtool/config/ltmain.sh config/
+rm -f libtool
+./bootstrap && ./configure && make && sudo make install
+==========
diff --git a/doc/ko/Makefile.am b/doc/ko/Makefile.am
new file mode 100644 (file)
index 0000000..b4ae2c5
--- /dev/null
@@ -0,0 +1,67 @@
+mandir = @mandir@/ko
+
+SUBDIRS =
+DIST_SUBDIRS =
+
+EXTRA_DIST = \
+       FAQ.txt
+
+if ENABLE_DOCBOOK
+man_MANS = \
+       lxc-attach.1 \
+       lxc-autostart.1 \
+       lxc-cgroup.1 \
+       lxc-checkconfig.1 \
+       lxc-checkpoint.1 \
+       lxc-config.1 \
+       lxc-console.1 \
+       lxc-copy.1 \
+       lxc-create.1 \
+       lxc-destroy.1 \
+       lxc-device.1 \
+       lxc-execute.1 \
+       lxc-freeze.1 \
+       lxc-info.1 \
+       lxc-ls.1 \
+       lxc-monitor.1 \
+       lxc-snapshot.1 \
+       lxc-start.1 \
+       lxc-stop.1 \
+       lxc-top.1 \
+       lxc-unfreeze.1 \
+       lxc-unshare.1 \
+       lxc-user-nic.1 \
+       lxc-usernsexec.1 \
+       lxc-wait.1 \
+       \
+       lxc.conf.5 \
+       lxc.container.conf.5 \
+       lxc.system.conf.5 \
+       lxc-usernet.5 \
+       \
+       lxc.7
+
+if ENABLE_DEPRECATED
+    man_MANS += lxc-clone.1
+if ENABLE_PYTHON
+    man_MANS += lxc-start-ephemeral.1
+endif
+endif
+
+%.1 : %.sgml
+       $(db2xman) --encoding=UTF-8 $<
+       test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+%.5 : %.sgml
+       $(db2xman) --encoding=UTF-8 $<
+       test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+%.7 : %.sgml
+       $(db2xman) --encoding=UTF-8 $<
+       test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+lxc-%.sgml : common_options.sgml see_also.sgml
+
+clean-local:
+       $(RM) manpage.* *.7 *.5 *.1 $(man_MANS)
+endif
diff --git a/doc/ko/Makefile.in b/doc/ko/Makefile.in
new file mode 100644 (file)
index 0000000..1520869
--- /dev/null
@@ -0,0 +1,959 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@am__append_1 = lxc-clone.1
+@ENABLE_DEPRECATED_TRUE@@ENABLE_DOCBOOK_TRUE@@ENABLE_PYTHON_TRUE@am__append_2 = lxc-start-ephemeral.1
+subdir = doc/ko
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
+       $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES = lxc-attach.sgml lxc-autostart.sgml \
+       lxc-cgroup.sgml lxc-checkconfig.sgml lxc-checkpoint.sgml \
+       lxc-clone.sgml lxc-config.sgml lxc-console.sgml lxc-copy.sgml \
+       lxc-create.sgml lxc-destroy.sgml lxc-device.sgml \
+       lxc-execute.sgml lxc-freeze.sgml lxc-info.sgml lxc-ls.sgml \
+       lxc-monitor.sgml lxc-snapshot.sgml lxc-start-ephemeral.sgml \
+       lxc-start.sgml lxc-stop.sgml lxc-top.sgml lxc-unfreeze.sgml \
+       lxc-unshare.sgml lxc-user-nic.sgml lxc-usernsexec.sgml \
+       lxc-wait.sgml lxc.conf.sgml lxc.container.conf.sgml \
+       lxc.system.conf.sgml lxc-usernet.sgml lxc.sgml \
+       common_options.sgml see_also.sgml
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+       ctags-recursive dvi-recursive html-recursive info-recursive \
+       install-data-recursive install-dvi-recursive \
+       install-exec-recursive install-html-recursive \
+       install-info-recursive install-pdf-recursive \
+       install-ps-recursive install-recursive installcheck-recursive \
+       installdirs-recursive pdf-recursive ps-recursive \
+       tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \
+       "$(DESTDIR)$(man7dir)"
+man5dir = $(mandir)/man5
+man7dir = $(mandir)/man7
+NROFF = nroff
+MANS = $(man_MANS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+       distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+       $(srcdir)/common_options.sgml.in $(srcdir)/lxc-attach.sgml.in \
+       $(srcdir)/lxc-autostart.sgml.in $(srcdir)/lxc-cgroup.sgml.in \
+       $(srcdir)/lxc-checkconfig.sgml.in \
+       $(srcdir)/lxc-checkpoint.sgml.in $(srcdir)/lxc-clone.sgml.in \
+       $(srcdir)/lxc-config.sgml.in $(srcdir)/lxc-console.sgml.in \
+       $(srcdir)/lxc-copy.sgml.in $(srcdir)/lxc-create.sgml.in \
+       $(srcdir)/lxc-destroy.sgml.in $(srcdir)/lxc-device.sgml.in \
+       $(srcdir)/lxc-execute.sgml.in $(srcdir)/lxc-freeze.sgml.in \
+       $(srcdir)/lxc-info.sgml.in $(srcdir)/lxc-ls.sgml.in \
+       $(srcdir)/lxc-monitor.sgml.in $(srcdir)/lxc-snapshot.sgml.in \
+       $(srcdir)/lxc-start-ephemeral.sgml.in \
+       $(srcdir)/lxc-start.sgml.in $(srcdir)/lxc-stop.sgml.in \
+       $(srcdir)/lxc-top.sgml.in $(srcdir)/lxc-unfreeze.sgml.in \
+       $(srcdir)/lxc-unshare.sgml.in $(srcdir)/lxc-user-nic.sgml.in \
+       $(srcdir)/lxc-usernet.sgml.in $(srcdir)/lxc-usernsexec.sgml.in \
+       $(srcdir)/lxc-wait.sgml.in $(srcdir)/lxc.conf.sgml.in \
+       $(srcdir)/lxc.container.conf.sgml.in $(srcdir)/lxc.sgml.in \
+       $(srcdir)/lxc.system.conf.sgml.in $(srcdir)/see_also.sgml.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_LIBS = @APPARMOR_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINDIR = @BINDIR@
+CAP_LIBS = @CAP_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CGMANAGER_CFLAGS = @CGMANAGER_CFLAGS@
+CGMANAGER_LIBS = @CGMANAGER_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIR = @DATADIR@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFAULT_CGROUP_PATTERN = @DEFAULT_CGROUP_PATTERN@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOCDIR = @DOCDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+HAVE_DOXYGEN = @HAVE_DOXYGEN@
+INCLUDEDIR = @INCLUDEDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBEXECDIR = @LIBEXECDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LOCALSTATEDIR = @LOCALSTATEDIR@
+LOGPATH = @LOGPATH@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBDIR = @LUA_LIBDIR@
+LUA_LIBS = @LUA_LIBS@
+LUA_SHAREDIR = @LUA_SHAREDIR@
+LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
+LXCHOOKDIR = @LXCHOOKDIR@
+LXCINITDIR = @LXCINITDIR@
+LXCPATH = @LXCPATH@
+LXCROOTFSMOUNT = @LXCROOTFSMOUNT@
+LXCTEMPLATECONFIG = @LXCTEMPLATECONFIG@
+LXCTEMPLATEDIR = @LXCTEMPLATEDIR@
+LXC_DEFAULT_CONFIG = @LXC_DEFAULT_CONFIG@
+LXC_DISTRO_SYSCONF = @LXC_DISTRO_SYSCONF@
+LXC_GENERATE_DATE = @LXC_GENERATE_DATE@
+LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
+LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
+LXC_USERNIC_DB = @LXC_USERNIC_DB@
+LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
+LXC_VERSION_BASE = @LXC_VERSION_BASE@
+LXC_VERSION_BETA = @LXC_VERSION_BETA@
+LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
+LXC_VERSION_MICRO = @LXC_VERSION_MICRO@
+LXC_VERSION_MINOR = @LXC_VERSION_MINOR@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NIH_CFLAGS = @NIH_CFLAGS@
+NIH_DBUS_CFLAGS = @NIH_DBUS_CFLAGS@
+NIH_DBUS_LIBS = @NIH_DBUS_LIBS@
+NIH_LIBS = @NIH_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PREFIX = @PREFIX@
+PYTHON = @PYTHON@
+PYTHONDEV_CFLAGS = @PYTHONDEV_CFLAGS@
+PYTHONDEV_LIBS = @PYTHONDEV_LIBS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RUNTIME_PATH = @RUNTIME_PATH@
+SBINDIR = @SBINDIR@
+SECCOMP_CFLAGS = @SECCOMP_CFLAGS@
+SECCOMP_LIBS = @SECCOMP_LIBS@
+SED = @SED@
+SELINUX_LIBS = @SELINUX_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSCONFDIR = @SYSCONFDIR@
+SYSTEMD_UNIT_DIR = @SYSTEMD_UNIT_DIR@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+db2xman = @db2xman@
+docdir = @docdir@
+docdtd = @docdtd@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@/ko
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = 
+DIST_SUBDIRS = 
+EXTRA_DIST = \
+       FAQ.txt
+
+@ENABLE_DOCBOOK_TRUE@man_MANS = lxc-attach.1 lxc-autostart.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-cgroup.1 lxc-checkconfig.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-checkpoint.1 lxc-config.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-console.1 lxc-copy.1 lxc-create.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-destroy.1 lxc-device.1 lxc-execute.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-freeze.1 lxc-info.1 lxc-ls.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-monitor.1 lxc-snapshot.1 lxc-start.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-stop.1 lxc-top.1 lxc-unfreeze.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-unshare.1 lxc-user-nic.1 \
+@ENABLE_DOCBOOK_TRUE@  lxc-usernsexec.1 lxc-wait.1 lxc.conf.5 \
+@ENABLE_DOCBOOK_TRUE@  lxc.container.conf.5 lxc.system.conf.5 \
+@ENABLE_DOCBOOK_TRUE@  lxc-usernet.5 lxc.7 $(am__append_1) \
+@ENABLE_DOCBOOK_TRUE@  $(am__append_2)
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/ko/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu doc/ko/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+lxc-attach.sgml: $(top_builddir)/config.status $(srcdir)/lxc-attach.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-autostart.sgml: $(top_builddir)/config.status $(srcdir)/lxc-autostart.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-cgroup.sgml: $(top_builddir)/config.status $(srcdir)/lxc-cgroup.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-checkconfig.sgml: $(top_builddir)/config.status $(srcdir)/lxc-checkconfig.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-checkpoint.sgml: $(top_builddir)/config.status $(srcdir)/lxc-checkpoint.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-clone.sgml: $(top_builddir)/config.status $(srcdir)/lxc-clone.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-config.sgml: $(top_builddir)/config.status $(srcdir)/lxc-config.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-console.sgml: $(top_builddir)/config.status $(srcdir)/lxc-console.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-copy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-copy.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-create.sgml: $(top_builddir)/config.status $(srcdir)/lxc-create.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-destroy.sgml: $(top_builddir)/config.status $(srcdir)/lxc-destroy.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-device.sgml: $(top_builddir)/config.status $(srcdir)/lxc-device.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-execute.sgml: $(top_builddir)/config.status $(srcdir)/lxc-execute.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-freeze.sgml: $(top_builddir)/config.status $(srcdir)/lxc-freeze.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-info.sgml: $(top_builddir)/config.status $(srcdir)/lxc-info.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-ls.sgml: $(top_builddir)/config.status $(srcdir)/lxc-ls.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-monitor.sgml: $(top_builddir)/config.status $(srcdir)/lxc-monitor.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-snapshot.sgml: $(top_builddir)/config.status $(srcdir)/lxc-snapshot.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-start-ephemeral.sgml: $(top_builddir)/config.status $(srcdir)/lxc-start-ephemeral.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-start.sgml: $(top_builddir)/config.status $(srcdir)/lxc-start.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-stop.sgml: $(top_builddir)/config.status $(srcdir)/lxc-stop.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-top.sgml: $(top_builddir)/config.status $(srcdir)/lxc-top.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-unfreeze.sgml: $(top_builddir)/config.status $(srcdir)/lxc-unfreeze.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-unshare.sgml: $(top_builddir)/config.status $(srcdir)/lxc-unshare.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-user-nic.sgml: $(top_builddir)/config.status $(srcdir)/lxc-user-nic.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-usernsexec.sgml: $(top_builddir)/config.status $(srcdir)/lxc-usernsexec.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-wait.sgml: $(top_builddir)/config.status $(srcdir)/lxc-wait.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc.conf.sgml: $(top_builddir)/config.status $(srcdir)/lxc.conf.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc.container.conf.sgml: $(top_builddir)/config.status $(srcdir)/lxc.container.conf.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc.system.conf.sgml: $(top_builddir)/config.status $(srcdir)/lxc.system.conf.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-usernet.sgml: $(top_builddir)/config.status $(srcdir)/lxc-usernet.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc.sgml: $(top_builddir)/config.status $(srcdir)/lxc.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+common_options.sgml: $(top_builddir)/config.status $(srcdir)/common_options.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+see_also.sgml: $(top_builddir)/config.status $(srcdir)/see_also.sgml.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-man1: $(man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(man_MANS)'; \
+       test -n "$(man1dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.1[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-man5: $(man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(man_MANS)'; \
+       test -n "$(man5dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.5[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man5:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man5dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.5[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+install-man7: $(man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(man_MANS)'; \
+       test -n "$(man7dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man7dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man7dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.7[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man7dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man7dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man7dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man7dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man7:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man7dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.7[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man7dir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+       @fail=; \
+       if $(am__make_keepgoing); then \
+         failcom='fail=yes'; \
+       else \
+         failcom='exit 1'; \
+       fi; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       $(am__define_uniq_tagged_files); \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       $(am__define_uniq_tagged_files); \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+       list='$(am__tagged_files)'; \
+       case "$(srcdir)" in \
+         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+         *) sdir=$(subdir)/$(srcdir) ;; \
+       esac; \
+       for i in $$list; do \
+         if test -f "$$i"; then \
+           echo "$(subdir)/$$i"; \
+         else \
+           echo "$$sdir/$$i"; \
+         fi; \
+       done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(MANS)
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man7dir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+@ENABLE_DOCBOOK_FALSE@clean-local:
+clean: clean-recursive
+
+clean-am: clean-generic clean-local mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man: install-man1 install-man5 install-man7
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1 uninstall-man5 uninstall-man7
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+       check-am clean clean-generic clean-local cscopelist-am ctags \
+       ctags-am distclean distclean-generic distclean-tags distdir \
+       dvi dvi-am html html-am info info-am install install-am \
+       install-data install-data-am install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-man install-man1 \
+       install-man5 install-man7 install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+       pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+       uninstall-man uninstall-man1 uninstall-man5 uninstall-man7
+
+.PRECIOUS: Makefile
+
+
+@ENABLE_DOCBOOK_TRUE@%.1 : %.sgml
+@ENABLE_DOCBOOK_TRUE@  $(db2xman) --encoding=UTF-8 $<
+@ENABLE_DOCBOOK_TRUE@  test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+@ENABLE_DOCBOOK_TRUE@%.5 : %.sgml
+@ENABLE_DOCBOOK_TRUE@  $(db2xman) --encoding=UTF-8 $<
+@ENABLE_DOCBOOK_TRUE@  test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+@ENABLE_DOCBOOK_TRUE@%.7 : %.sgml
+@ENABLE_DOCBOOK_TRUE@  $(db2xman) --encoding=UTF-8 $<
+@ENABLE_DOCBOOK_TRUE@  test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
+
+@ENABLE_DOCBOOK_TRUE@lxc-%.sgml : common_options.sgml see_also.sgml
+
+@ENABLE_DOCBOOK_TRUE@clean-local:
+@ENABLE_DOCBOOK_TRUE@  $(RM) manpage.* *.7 *.5 *.1 $(man_MANS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/ko/common_options.sgml.in b/doc/ko/common_options.sgml.in
new file mode 100644 (file)
index 0000000..a7c405e
--- /dev/null
@@ -0,0 +1,173 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <dlezcano at fr.ibm.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<refsect1>
+  <title><!-- Common Options -->공통 옵션</title>
+
+  <para>
+    <!--
+    These options are common to most of lxc commands.
+    -->
+    이 옵션들은 대부분의 lxc 명령어들에서 공통으로 쓰인다.
+  </para>
+
+  <variablelist>
+    <varlistentry>
+      <term><option>-?, -h, --help</option></term>
+      <listitem>
+       <para>
+          <!--
+         Print a longer usage message than normal.
+          -->
+          사용법을 기존 출력하는 것보다 길게 출력한다.
+       </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term><option>--usage</option></term>
+      <listitem>
+       <para>
+          <!--
+         Give the usage message
+          -->
+          사용법을 표시한다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>-q, --quiet</option></term>
+      <listitem>
+       <para>
+          <!--
+         mute on
+          -->
+          결과를 표시하지 않는다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>-P, --lxcpath=<replaceable>PATH</replaceable></option></term>
+      <listitem>
+       <para>
+          <!--
+         Use an alternate container path.  The default is @LXCPATH@.
+          -->
+          컨테이너 경로를 직접 지정한다. 기본값은 @LXCPATH@이다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>-o, --logfile=<replaceable>FILE</replaceable></option></term>
+      <listitem>
+       <para>
+          <!--
+         Output to an alternate log
+         <replaceable>FILE</replaceable>. The default is no log.
+          -->
+          로그의 경로를 <replaceable>FILE</replaceable>로 지정한다. 기본값은 로그를 출력하지 않는 것이다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>-l, --logpriority=<replaceable>LEVEL</replaceable></option></term>
+      <listitem>
+       <para>
+          <!--
+         Set log priority to
+         <replaceable>LEVEL</replaceable>. The default log
+         priority is <literal>ERROR</literal>. Possible values are :
+         <literal>FATAL</literal>, <literal>CRIT</literal>,
+         <literal>WARN</literal>, <literal>ERROR</literal>,
+         <literal>NOTICE</literal>, <literal>INFO</literal>,
+         <literal>DEBUG</literal>.
+          -->
+          로그 수준을 <replaceable>LEVEL</replaceable>로 지정한다. 기본값은 <literal>ERROR</literal>이다. 사용 가능한 값 :
+         <literal>FATAL</literal>, <literal>CRIT</literal>,
+         <literal>WARN</literal>, <literal>ERROR</literal>,
+         <literal>NOTICE</literal>, <literal>INFO</literal>,
+         <literal>DEBUG</literal>.
+       </para>
+       <para>
+          <!--
+       Note that this option is setting the priority of the events
+       log in the alternate log file. It do not have effect on the
+       ERROR events log on stderr.
+        -->
+          이 옵션은 로그 파일에만 적용된다는 사실을 주의해야 한다. stderr로 출력되는 ERROR 로그에는 영향을 끼치지 않는다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>-n, --name=<replaceable>NAME</replaceable></option></term>
+      <listitem>
+       <para>
+          <!--
+         Use container identifier <replaceable>NAME</replaceable>.
+         The container identifier format is an alphanumeric string.
+          -->
+          컨테이너 식별자로 <replaceable>NAME</replaceable>을 사용한다. 컨테이너 식별자의 형식은 알파벳-숫자 문자열이다.
+       </para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+      <term><option>--version</option></term>
+      <listitem>
+       <para>
+          <!--
+         Show the version number.
+          -->
+          버전 정보를 표시한다.
+       </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+
+</refsect1>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-attach.sgml.in b/doc/ko/lxc-attach.sgml.in
new file mode 100644 (file)
index 0000000..4f0a22c
--- /dev/null
@@ -0,0 +1,484 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-attach</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-attach</refname>
+
+    <refpurpose>
+      <!--
+      start a process inside a running container.
+      -->
+      실행 중인 컨테이너 내에 프로세스를 실행
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-attach</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-a <replaceable>arch</replaceable></arg>
+      <arg choice="opt">-e</arg>
+      <arg choice="opt">-s <replaceable>namespaces</replaceable></arg>
+      <arg choice="opt">-R</arg>
+      <arg choice="opt">--keep-env</arg>
+      <arg choice="opt">--clear-env</arg>
+      <arg choice="opt">-- <replaceable>command</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-attach</command> runs the specified
+      <replaceable>command</replaceable> inside the container
+      specified by <replaceable>name</replaceable>. The container
+      has to be running already.
+      -->
+      <command>lxc-attach</command>는  <replaceable>name</replaceable>으로 지정한 컨테이너 내에  <replaceable>command</replaceable>를 실행한다.
+      해당 컨테이너는 실행중이어야 한다.
+    </para>
+    <para>
+      <!--
+      If no <replaceable>command</replaceable> is specified, the
+      current default shell of the user running
+      <command>lxc-attach</command> will be looked up inside the
+      container and executed. This will fail if no such user exists
+      inside the container or the container does not have a working
+      nsswitch mechanism.
+      -->
+      만약 <replaceable>command</replaceable>가 지정되지 않았다면, <command>lxc-attach</command>가 현재 실행 중인 쉘이 컨테이너 안에도 있는지 검사하고 이를 실행한다.
+      만약 컨테이너 안에 사용자가 존재하지 않거나, nsswitch가 제대로 동작하지 않는 경우에는 이 명령이 실패하게 된다.
+    </para>
+    <para>
+      <!--
+      Previous versions of <command>lxc-attach</command> simply attached to the
+      specified namespaces of a container and ran a shell or the specified command
+      without first allocating a pseudo terminal. This made them vulnerable to
+      input faking via a TIOCSTI <command>ioctl</command> call after switching
+      between userspace execution contexts with different privilege levels. Newer
+      versions of <command>lxc-attach</command> will try to allocate a pseudo
+      terminal master/slave pair on the host and attach any standard file
+      descriptors which refer to a terminal to the slave side of the pseudo
+      terminal before executing a shell or command. Note, that if none of the
+      standard file descriptors refer to a terminal <command>lxc-attach</command>
+      will not try to allocate a pseudo terminal. Instead it will simply attach
+      to the containers namespaces and run a shell or the specified command.
+      -->
+      이전 버전의 <command>lxc-attach</command>는 단순히 컨테이너의 특정 네임스페이스에 붙어, 쉘을 실행하거나 첫 번째 pseudo 터미널 할당 없이 특정 명령어를 실행하였다.
+      이는 다른 특권 수준을 갖는 사용자 영역 컨텍스트 간의 전환후 TIOCSTI <command>ioctl</command>를 호출하여 입력을 가로챌 수 있는 취약점이 있다.
+      새로운 버전의 <command>lxc-attach</command>는 쉘이나 명령어를 실행하기 전에, pseudo 터미널 마스터/슬레이브 쌍을 호스트에 할당하고 터미널을 가리키고 있던 표준 입출력 파일 디스크립터들은 슬레이브 pseudo 터미널로 붙인다.
+      터미널을 가리키고 있던 표준 입출력 파일 디스크립터가 아예 없었다면, <command>lxc-attach</command>는 pseudo 터미널 할당을 시도하지 않음에 주의해야 한다. 단순히 컨테이너 네임스페이스에 붙어 쉘이나 지정한 명령어만 실행할 뿐이다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-a, --arch <replaceable>arch</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the architecture which the kernel should appear to be
+           running as to the command executed. This option will accept the
+           same settings as the <option>lxc.arch</option> option in
+           container configuration files, see
+           <citerefentry>
+             <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+             <manvolnum>5</manvolnum>
+           </citerefentry>. By default, the current archictecture of the
+           running container will be used.
+            -->
+            명령어를 실행하는 컨테이너의 아키텍처를 지정한다.
+            이 옵션은 컨테이너의 설정파일에서 지정한 <option>lxc.arch</option> 옵션과 같은 것만 사용할 수 있다.
+            <citerefentry>
+             <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+             <manvolnum>5</manvolnum>
+           </citerefentry>를 참조 바란다. 기본값은 실행 중인 컨테이너의 아키텍처이다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>
+           -e, --elevated-privileges <replaceable>privileges</replaceable>
+         </option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Do not drop privileges when running
+           <replaceable>command</replaceable> inside the container. If
+           this option is specified, the new process will
+           <emphasis>not</emphasis> be added to the container's cgroup(s)
+           and it will not drop its capabilities before executing.
+            -->
+            컨테이너 내부에서 <replaceable>command</replaceable>를 실행할 때 privilege를 제거하지 않는다.
+            만약 이 옵션이 지정되었다면, 새로운 프로세스는 컨테이너의 cgroup에 추가되지 <emphasis>않는다</emphasis>. 그리고 실행 전 capability도 제거하지 않는다.
+         </para>
+          <para>
+           <!--
+           You may specify privileges, in case you do not want to elevate all of
+           them, as a pipe-separated list, e.g.
+           <replaceable>CGROUP|LSM</replaceable>. Allowed values are
+           <replaceable>CGROUP</replaceable>, <replaceable>CAP</replaceable> and
+           <replaceable>LSM</replaceable> representing cgroup, capabilities and
+           restriction privileges respectively. (The pipe symbol needs to be escaped,
+           e.g. <replaceable>CGROUP\|LSM</replaceable> or quoted, e.g.
+           <replaceable>"CGROUP|LSM"</replaceable>.)
+           -->
+            만약 모든 privilege를 얻고 싶지 않을 경우에는 <replaceable>CGROUP|LSM</replaceable>와 같이 파이프(|)로 구분된 리스트를 사용할 수 있다. 허용되는 값은 <replaceable>CGROUP</replaceable>、<replaceable>CAP</replaceable>、<replaceable>LSM</replaceable>이다. 각각 cgroup, capability, MAC label을 나타낸다.
+            (파이프 기호는 <replaceable>CGROUP\|LSM</replaceable>처럼 \로 처리를 해주거나, <replaceable>"CGROUP|LSM"</replaceable>처럼 따옴표를 붙여야 한다.)
+          </para>
+         <para>
+            <!--
+           <emphasis>Warning:</emphasis> This may leak privileges into the
+           container if the command starts subprocesses that remain active
+           after the main process that was attached is terminated. The
+           (re-)starting of daemons inside the container is problematic,
+           especially if the daemon starts a lot of subprocesses such as
+           <command>cron</command> or <command>sshd</command>.
+           <emphasis>Use with great care.</emphasis>
+            -->
+            <emphasis>경고 :</emphasis>
+            만약 명령어가 attach된 메인프로세스가 종료된 후에, 실행 상태로 남아있는 서브프로세스를 시작하려고 한다면, 컨테이너 내부로 privilege 누수가 발생할 수 있다.
+            컨테이너 내에서 데몬을 시작(또는 재시작)하는 것은 문제가 될 수 있다.            특히 만약 데몬이 많은 서브프로세스 를 실행하는 경우라면, 예를 들어  <command>cron</command>와 <command>sshd</command>와 같은 경우는 문제가 될 수 있다.
+            <emphasis>충분한 주의를 기울여서 사용하여야 한다.</emphasis>
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-s, --namespaces <replaceable>namespaces</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the namespaces to attach to, as a pipe-separated list,
+           e.g. <replaceable>NETWORK|IPC</replaceable>. Allowed values are
+           <replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>,
+           <replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>,
+           <replaceable>USER </replaceable> and
+           <replaceable>NETWORK</replaceable>. This allows one to change
+           the context of the process to e.g. the network namespace of the
+           container while retaining the other namespaces as those of the
+            host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
+            -->
+            붙일 네임스페이스를 지정한다. <replaceable>NETWORK|IPC</replaceable>와 같이 파이프(|)로 구분된 리스트를 사용할 수 있다. 허용되는 값은 <replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>, <replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>, <replaceable>USER </replaceable>, <replaceable>NETWORK</replaceable>이다. 이를 사용하여, 컨테이너의 네트워크 네임스페이스를 사용하면서도 다른 네임스페이스는 호스트의 것을 그대로 사용하는 등의 조작이 가능하다.
+            (파이프 기호는 <replaceable>MOUNT\|PID</replaceable>처럼 \로 처리를 해주거나, <replaceable>"MOUNT|PID"</replaceable>처럼 따옴표를 붙여야 한다.)
+         </para>
+         <para>
+            <!--
+           <emphasis>Important:</emphasis> This option implies
+           <option>&#045;e</option>.
+            -->
+            <emphasis>중요 :</emphasis> 이 옵션은 <option>-e</option> 옵션을 포함하고 있다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-R, --remount-sys-proc</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           When using <option>&#045;s</option> and the mount namespace is not
+           included, this flag will cause <command>lxc-attach</command>
+           to remount <replaceable>/proc</replaceable> and
+           <replaceable>/sys</replaceable> to reflect the current other
+           namespace contexts.
+            -->
+            <option>-s</option>를 사용하여 마운트 네임스페이스를 포함하지 않았을 때, 이 플래그는 <command>lxc-attach</command>가 <replaceable>/proc</replaceable>와 <replaceable>/sys</replaceable>를 remount 하게 만든다.
+            이는 현재와 다른 네임스페이스 컨텍스트를 반영시키기 위함이다.
+         </para>
+         <para>
+            <!--
+           Please see the <emphasis>Notes</emphasis> section for more
+           details.
+            -->
+            좀더 자세한 설명은 <emphasis>주의</emphasis>섹션을 참고하면 된다.
+         </para>
+         <para>
+            <!--
+           This option will be ignored if one tries to attach to the
+           mount namespace anyway.
+            -->
+            만약 마운트 네임스페이스에 attach하려고 한다면, 이 옵션은 무시된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--keep-env</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Keep the current environment for attached programs. This is
+           the current default behaviour (as of version 0.9), but is
+           is likely to change in the future, since this may leak
+           undesirable information into the container. If you rely on
+           the environment being available for the attached program,
+           please use this option to be future-proof. In addition to
+           current environment variables, container=lxc will be set.
+            -->
+            현재의 환경변수를 attach될 프로그램에도 그대로 적용한다. 이것은 현재 기본 동작이지만 (버전 0.9에서), 향후에 충분히 바뀔 수도 있다. 왜냐하면, 이것은 컨테이너에게 바람직하지 않은 정보를 넘겨줄 수 있는 위험성이 있기 때문이다. 따라서 이 기능에 의존하고 있다면, 향후에도 이를 보장할 수 있도록 이 옵션을 사용하는 것이 좋다. 또한 현재 환경 변수와 더불어, container=lxc도 설정된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--clear-env</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Clear the environment before attaching, so no undesired
+           environment variables leak into the container. The variable
+           container=lxc will be the only environment with which the
+           attached program starts.
+            -->
+            attach하기 전에 모든 환경변수를 지운다.
+            이를 통해 바람직하지 않은 환경변수 누출을 막을 수 있다. container=lxc 만이 attach된 프로그램이 실행되기 전에 설정되는 유일한 환경변수이다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+      <para>
+        <!--
+        To spawn a new shell running inside an existing container, use
+        <programlisting>
+          lxc-attach -n container
+        </programlisting>
+        -->
+        존재하는 컨테이너의 내부에 새로운 쉘을 실행한다.
+        <programlisting>
+          lxc-attach -n container
+        </programlisting>
+      </para>
+      <para>
+        <!--
+        To restart the cron service of a running Debian container, use
+        <programlisting>
+          lxc-attach -n container &#045;&#045; /etc/init.d/cron restart
+        </programlisting>
+        -->
+        실행중인 Debian 컨테이너의 cron 서비스를 재시작한다.
+        <programlisting>
+          lxc-attach -n container -- /etc/init.d/cron restart
+        </programlisting>
+      </para>
+      <para>
+        <!--
+        To deactivate the network link eth1 of a running container that
+        does not have the NET_ADMIN capability, use either the
+        <option>-e</option> option to use increased capabilities,
+        assuming the <command>ip</command> tool is installed:
+        <programlisting>
+          lxc-attach -n container -e &#045;&#045; /sbin/ip link delete eth1
+        </programlisting>
+        -->
+        NET_ADMIN capability없이 실행중인 컨테이너의 네트워크 링크 eth1을 비활성화하였다. <option>-e</option> 옵션을 사용하여 capability를 높였고, <command>ip</command> 툴이 설치되어있다고 가정하였다.
+        <programlisting>
+          lxc-attach -n container -e -- /sbin/ip link delete eth1
+        </programlisting>
+      </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Compatibility -->호환성</title>
+    <para>
+      <!--
+      Attaching completely (including the pid and mount namespaces) to a
+      container requires a kernel of version 3.8 or higher, or a
+      patched kernel, please see the lxc website for
+      details. <command>lxc-attach</command> will fail in that case if
+      used with an unpatched kernel of version 3.7 and prior.
+      -->
+      (pid와 마운트 네임스페이스를 포함한) attach가 동작하기 위해서는 커널의 버전이 3.8 이상이거나 패치가 적용된 커널이어야 한다. 좀더 자세히 보려면 lxc 웹사이트를 참고하면 된다. <command>lxc-attach</command>는 패치되지 않은 커널 버전 3.7 이하면 실패된다.
+    </para>
+    <para>
+      <!--
+      Nevertheless, it will succeed on an unpatched kernel of version 3.0
+      or higher if the <option>-s</option> option is used to restrict the
+      namespaces that the process is to be attached to to one or more of
+      <replaceable>NETWORK</replaceable>, <replaceable>IPC</replaceable>
+      and <replaceable>UTSNAME</replaceable>.
+      -->
+      그러나 <option>-s</option>를 사용하여 <replaceable>NETWORK</replaceable>, <replaceable>IPC</replaceable>, <replaceable>UTSNAME</replaceable> 네임스페이스 들만 지정한다면, 패치되지 않은 커널 3.0 이상에서도 성공적으로 동작한다.
+    </para>
+    <para>
+      <!--
+      Attaching to user namespaces is supported by kernel 3.8 or higher
+      with enabling user namespace.
+      -->
+      사용자 네임스페이스에 attach하기 위해서는 커널 버전이 3.8 이상이어야 하고 사용자 네임스페이스가 활성화되어야 한다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Notes -->주의</title>
+    <para>
+      <!--
+      The Linux <replaceable>/proc</replaceable> and
+      <replaceable>/sys</replaceable> filesystems contain information
+      about some quantities that are affected by namespaces, such as
+      the directories named after process ids in
+      <replaceable>/proc</replaceable> or the network interface information
+      in <replaceable>/sys/class/net</replaceable>. The namespace of the
+      process mounting the pseudo-filesystems determines what information
+      is shown, <emphasis>not</emphasis> the namespace of the process
+      accessing <replaceable>/proc</replaceable> or
+      <replaceable>/sys</replaceable>.
+      -->
+      리눅스의 <replaceable>/proc</replaceable>와 <replaceable>/sys</replaceable> 파일시스템은 네임스페이스의해 영향받는 몇가지 정보들을 포함하고 있다. 예를 들어 <replaceable>/proc</replaceable>의 프로세스 id로 된 폴더들이나 <replaceable>/sys/class/net</replaceable>의 네트워크 인터페이스 정보 등이다.
+의사파일시스템을 마운트하는 프로세스의 네임스페이스가 여기에 어떤 정보를 표시할지 결정하는 것이지, <replaceable>/proc</replaceable> 또는 <replaceable>/sys</replaceable>에 접근하는 프로세스의 네임스페이스가 결정하는 것은 <emphasis>아니다.</emphasis>
+    </para>
+    <para>
+      <!--
+      If one uses the <option>-s</option> option to only attach to
+      the pid namespace of a container, but not its mount namespace
+      (which will contain the <replaceable>/proc</replaceable> of the
+      container and not the host), the contents of <option>/proc</option>
+      will reflect that of the host and not the container. Analogously,
+      the same issue occurs when reading the contents of
+      <replaceable>/sys/class/net</replaceable> and attaching to just
+      the network namespace.
+      -->
+      <option>-s</option> 를 사용하여 컨테이너의 pid 네임스페이스에만 attach 시키고 마운트 네임스페이스(컨테이너의 <replaceable>/proc</replaceable>는 포함하고, 호스트의 것은 포함하지 않는)는 attach 시키지 않는 경우, <option>/proc</option>의 내용은 컨테이너의 것이 아닌 호스트의 것이 된다.
+네트워크 네임스페이스만을 연결하고  <replaceable>/sys/class/net</replaceable>의 내용을 읽을 때도 같은 현상이 있다.
+    </para>
+    <para>
+      <!--
+      To work around this problem, the <option>-R</option> flag provides
+      the option to remount <replaceable>/proc</replaceable> and
+      <replaceable>/sys</replaceable> in order for them to reflect the
+      network/pid namespace context of the attached process. In order
+      not to interfere with the host's actual filesystem, the mount
+      namespace will be unshared (like <command>lxc-unshare</command>
+      does) before this is done, essentially giving the process a new
+      mount namespace, which is identical to the hosts's mount namespace
+      except for the <replaceable>/proc</replaceable> and
+      <replaceable>/sys</replaceable> filesystems.
+      -->
+      이러한 문제를 해결하기 위해, <option>-R</option> 옵션이 제공된다. 해당 옵션은 attach되는 프로세스의 네트워크/pid 네임스페이스를 반영하기 위해 <replaceable>/proc</replaceable>와 <replaceable>/sys</replaceable>를 다시 마운트한다.
+호스트의 실제 파일시스템에 방해가 되지 않기 위해 마운트 네임스페이스는 공유되지 않는다(<command>lxc-unshare</command>의 동작과 비슷). <replaceable>/proc</replaceable>와 <replaceable>/sys</replaceable> 파일시스템을 제외하고 호스트 마운트 네임스페이스와 동일한 새로운 마운트 네임스페이스가 주어지게 된다.
+    </para>
+
+    <para>
+      <!--
+      Previous versions of <command>lxc-attach</command> suffered a bug whereby
+      a user could attach to a containers namespace without being placed in a
+      writeable cgroup for some critical subsystems. Newer versions of
+      <command>lxc-attach</command> will check whether a user is in a writeable
+      cgroup for those critical subsystems. <command>lxc-attach</command> might
+      thus fail unexpectedly for some users (E.g. on systems where an
+      unprivileged user is not placed in a writeable cgroup in critical
+      subsystems on login.). However, this behavior is correct and more secure.
+      -->
+      이전 버전의 <command>lxc-attach</command>는 몇몇 중요한 서브시스템에 쓰기가 가능한 cgroup 내에 없더라도, 사용자가 컨테이너의 네임스페이스에 연결할 수 있는 버그가 있었다.
+      새로운 버전의 <command>lxc-attach</command>는 현재 사용자가 몇몇 중요한 서브시스템에 쓰기 권한이 있는 cgroup에 속하는지 여부를 검사한다. 그러므로 <command>lxc-attach</command>는 사용자에 따라 실패하는 경우도 있다. (예를 들어, 로그인 시 비특권 사용자가 중요 서브시스템에 쓰기가 가능한 cgroup에 위치하지 않은 경우) 하지만 이러한 동작은 정확한 것이고 더 안전한 것이다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Security -->보안</title>
+    <para>
+      <!--
+      The <option>-e</option> and <option>-s</option> options should
+      be used with care, as it may break the isolation of the containers
+      if used improperly.
+      -->
+      <option>-e</option>와 <option>-s</option> 옵션을 사용할때는 주의해야 한다. 잘못 사용하게 하면 컨테이너들 간의 고립(isolation)을 깨트릴 수 있다.
+    </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-autostart.sgml.in b/doc/ko/lxc-autostart.sgml.in
new file mode 100644 (file)
index 0000000..c8d38c0
--- /dev/null
@@ -0,0 +1,350 @@
+<!--
+
+lxc-autostart
+
+(C) Copyright 2013 Canonical Ltd.
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+    <!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+    <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+    <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+    <refmeta>
+        <refentrytitle>lxc-autostart</refentrytitle>
+        <manvolnum>1</manvolnum>
+    </refmeta>
+
+    <refnamediv>
+        <refname>lxc-autostart</refname>
+
+        <refpurpose>
+          <!--
+            start/stop/kill auto-started containers
+            -->
+          자동시작하게 설정된 컨테이너의 시작/종료/강제종료
+        </refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+        <cmdsynopsis>
+            <command>lxc-autostart</command>
+            <arg choice="opt">-k</arg>
+            <arg choice="opt">-L</arg>
+            <arg choice="opt">-r</arg>
+            <arg choice="opt">-s</arg>
+            <arg choice="opt">-a</arg>
+            <arg choice="opt">-A</arg>
+            <arg choice="opt">-g <replaceable>groups</replaceable></arg>
+            <arg choice="opt">-t <replaceable>timeout</replaceable></arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1>
+        <title><!-- Description -->설명</title>
+
+        <para>
+          <!--
+            <command>lxc-autostart</command> processes containers
+            with lxc.start.auto set. It lets the user start, shutdown,
+            kill, restart containers in the right order, waiting the
+            right time. Supports filtering by lxc.group or just run
+            against all defined containers. It can also be used by
+            external tools in list mode where no action will be performed
+            and the list of affected containers (and if relevant, delays)
+            will be shown.
+            -->
+          <command>lxc-autostart</command>는 lxc.start.auto가 설정되어 있는 컨테이너들을 다룬다.
+          사용자가 컨테이너의 시작, 종료, 강제종료, 재시작의 순서와 대기 시간을 정할 수 있게 해준다.
+          lxc.group으로 필터링하거나 모든 정의된 컨테이너를 실행하는 등의 동작을 지원한다.
+          또한 리스트 모드를 통해 외부 툴이 이를 사용할 수 있고, 대상 컨테이너의 리스트와 대기시간 등을 얻어올 수 있다.
+        </para>
+
+        <para>
+          <!--
+            The <optional>-r</optional>, <optional>-s</optional>
+            and <optional>-k</optional> options specify the action to perform.
+            If none is specified, then the containers will be started.
+            <optional>-a</optional> and <optional>-g</optional> are used to
+            specify which containers will be affected. By default only
+            containers without a lxc.group set will be affected.
+            <optional>-t TIMEOUT</optional> specifies the maximum amount
+            of time to wait for the container to complete the shutdown
+            or reboot.
+            -->
+          <optional>-r</optional>, <optional>-s</optional>, <optional>-k</optional> 옵션은 어떤 동작을 수행할지 지정해 줄 수 있다. 만약 아무것도 지정하지 않았다면, 컨테이너를 시작한다.
+          <optional>-a</optional>, <optional>-g</optional>는 어떤 컨테이너를 대상으로 할지 지정한다. 기본적으로 lxc.group가 지정되지 않은 컨테이너들이 대상이 된다.
+          <optional>-t TIMEOUT</optional>은 컨테이너가 종료나 재부팅을 마칠 때까지 기다릴 최대 시간을 지정한다.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title><!-- Options -->옵션</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-r,--reboot </option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Request a reboot of the container.
+                        -->
+                      컨테이너가 재부팅하도록 요청한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-s,--shutdown </option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Request a clean shutdown. If a
+                        <optional>-t timeout</optional> greater than 0 is
+                        given and the container has not shut down within
+                        this period, it will be killed as with the
+                        <optional>-k kill</optional> option.
+                        -->
+                       깔끔한 종료를 요청한다. 만약 <optional>-t timeout</optional>가 0보다 크고 컨테이너가 그 기간안에 종료되지 않는다면 <optional>-k kill</optional> 옵션과 같은 동작을 수행하여 강제종료 한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-k,--kill </option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Rather than requesting a clean shutdown of the
+                        container, explicitly kill all tasks in the container.
+                        -->
+                      깔끔한 종료를 요청하는 것이 아니라 컨테이너의 모든 태스크들을 명시적으로 강제종료 시킨다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-L,--list </option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Rather than performing the action, just print
+                        the container name and wait delays until starting the next container.
+                        -->
+                      실제 동작은 수행하지 않고, 단지 컨테이너의 이름과 다음 컨테이너를 시작할 때까지의 대기시간들을 표시한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-t,--timeout <replaceable>TIMEOUT</replaceable></option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Wait TIMEOUT seconds before hard-stopping the container.
+                        -->
+                      컨테이너가 강제종료되기 전까지 TIMEOUT 초만큼 기다린다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-g,--group <replaceable>GROUP</replaceable></option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Comma separated list of groups to select
+                        (defaults to those without a lxc.group - the NULL group).
+                        This option may be specified multiple times
+                        and the arguments concatenated.  The NULL or
+                        empty group may be specified as a leading comma,
+                        trailing comma, embedded double comma, or empty
+                        argument where the NULL group should be processed.
+                        Groups are processed in the order specified on the
+                        command line.  Multiple invocations of the -g option
+                        may be freely intermixed with the comma separated
+                        lists and will be combined in specified order.
+                        -->
+                      쉼표(,)로 구분된 선택할 그룹의 리스트.
+                      (기본값은 lxc.group이 없는 것이다 - NULL 그룹)
+
+                      이 옵션은 여러번 지정될 수 있으며, 각 옵션들은 연결될 수 있다. NULL 또는 빈 그룹은 첫번째 쉼표, 맨 뒤의 쉼표, 두개의 쉼표 등으로 지정할 수 있다. 그룹들은 지정한 순서대로 처리된다. 여러번 호출된 -g 옵션과 콤마로 구분된 목록들은 자유롭게 혼용하여 사용 할 수 있다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-a,--all</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Ignore lxc.group and select all auto-started containers.
+                        -->
+                      lxc.group를 무시하고 모든 자동 시작하게 설정된 컨테이너들을 선택한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-A,--ignore-auto</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Ignore the lxc.start.auto flag. Combined with
+                        -a, will select all containers on the system.
+                        -->
+                      lxc.start.auto 옵션을 무시하고 시스템의 모든 컨테이너를 선택한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    <refsect1>
+        <title><!-- Autostart and System Boot -->자동시작과 시스템 부팅</title>
+
+        <para>
+          <!--
+            The <command>lxc-autostart</command> command is used as part of the
+            LXC system service, when enabled to run on host system at bootup and at
+            shutdown.  It's used to select which containers to start in what order
+            and how much to delay between each startup when the host system boots.
+            -->
+          부팅과 종료시 호스트의 시스>템에서 실행되도록 활성화 되어있을 때, <command>lxc-autostart</command> 명령어는 LXC 시스템 서비스의 일부로 사용된다. 어떤 컨테이너를 어떤 순서로 얼마만큼 간격을 두어 시작할지 선택하는데 사용된다.
+        </para>
+
+        <para>
+          <!--
+            Each container can be part of any number of groups or no group at all.
+            Two groups are special. One is the NULL group, i.e. the container does
+            not belong to any group. The other group is the "onboot" group.
+            -->
+          각각의 컨테이너는 여러 그룹에 속할수도 있고 아무그룹에도 속하지 않을 수 있다. 두개의 그룹은 특수한데, 하나는 NULL 그룹이고 컨테이너가 아무그룹에도 속하지 않을때 사용된다. 그리고 나머지 하나는 "onboot" 그룹이다.
+        </para>
+
+        <para>
+          <!--
+            When the system boots with the LXC service enabled, it will first
+            attempt to boot any containers with lxc.start.auto == 1 that is a member
+            of the "onboot" group. The startup will be in order of lxc.start.order.
+            If an lxc.start.delay has been specified, that delay will be honored
+            before attempting to start the next container to give the current
+            container time to begin initialization and reduce overloading the host
+            system. After starting the members of the "onboot" group, the LXC system
+            will proceed to boot containers with lxc.start.auto == 1 which are not
+            members of any group (the NULL group) and proceed as with the onboot
+            group.
+            -->
+          LXC 서비스가 활성화된 상태로 시스템이 부팅될 때, 먼저 lxc.start.auto == 1이고 "onboot" 그룹인 컨테이너들을 시작하려고 시도한다. 시작과정은 lxc.start.order의 순서대로 이루어진다.
+          만약 lxc.start.delay가 지정 되었다면, 다음 컨테이너를 시작하려고 시도하기 전, 현재 컨테이너의 초기화 및 호스트 시스템의 부하를 줄이기 위해서 지연시간을 준다.
+          "onboot" 그룹의 멤버들을 시작시킨 후, LXC 시스템은 lxc.start.auto == 1이고 어떤 그룹에도 속하지 않은(NULL 그룹) 컨테이너들을 시작한다.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title><!-- Startup Group Examples -->시작 그룹 예제</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-g "onboot,"</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Start the "onboot" group first then the NULL group.
+                        -->
+                      먼저 "onboot" 그룹을 실행하고 NULL 그룹을 실행한다.
+                    </para>
+                    <para>
+                      <!--
+                        This is the equivalent of: <option>-g onboot -g ""</option>.
+                        -->
+                      이것은 다음과 같다 : <option>-g onboot -g ""</option>
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-g "dns,web,,onboot"</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Starts the "dns" group first, the "web" group second, then
+                        the NULL group followed by the "onboot" group.
+                        -->
+                      첫번째로 dns 그룹을 실행하고, web 그룹을 두번째로 실행하고, NULL그룹을 실행한 뒤, "onboot" 그룹을 실행한다.
+                    </para>
+                    <para>
+                      <!--
+                        This is the equivalent of: <option>-g dns,web -g ,onboot</option> or <option>-g dns -g web -g "" -g onboot</option>.
+                        -->
+                      이것은 다음과 같다 : <option>-g dns,web -g ,onboot</option> 또는  <option>-g dns -g web -g "" -g onboot</option>
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    &seealso;
+
+    <refsect1>
+        <title><!--Author-->저자</title>
+        <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+    </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-cgroup.sgml.in b/doc/ko/lxc-cgroup.sgml.in
new file mode 100644 (file)
index 0000000..9efb8d2
--- /dev/null
@@ -0,0 +1,206 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-cgroup</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-cgroup</refname>
+
+    <refpurpose>
+      <!--
+      manage the control group associated with a container
+      -->
+      컨테이너와 관련된 컨트롤 그룹 관리
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-cgroup</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="req"><replaceable>state-object</replaceable></arg>
+      <arg choice="opt">value</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-cgroup</command> gets or sets the value of a
+      <replaceable>state-object</replaceable> (e.g., 'cpuset.cpus')
+      in the container's cgroup for the corresponding subsystem (e.g.,
+      'cpuset'). If no <optional>value</optional> is specified, the
+      current value of the <replaceable>state-object</replaceable> is
+      displayed; otherwise it is set.
+      -->
+      <command>lxc-cgroup</command>는 지정한 서브시스템(예를 들어 'cpuset')의 컨테이너 cgroup의 <replaceable>state-object</replaceable> (예를들어 'cpuset.cpus')의 값을 얻어오거나 설정한다.
+      만약 <optional>value</optional>가 지정되지 않았다면, <replaceable>state-object</replaceable>의 현재 값을 표시한다. 지정한 경우에는 해당 값으로 설정한다.
+    </para>
+
+    <para>
+      <!--
+      Note that <command>lxc-cgroup</command> does not check that the
+      <replaceable>state-object</replaceable> is valid for the running
+      kernel, or that the corresponding subsystem is contained in any
+      mounted cgroup hierarchy.
+      -->
+      <command>lxc-cgroup</command>는 <replaceable>state-object</replaceable>가 실행중인 커널에서 사용가능한지 검사하지 않는 것을 주의해야 한다. 또한 지정한 서브시스템이 마운트된 cgroup에 포함이 되어 있는지도 검사하지 않는다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option><replaceable>state-object</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the state object name.
+            -->
+            cgroup의 state object 이름을 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option><optional>value</optional></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the value to assign to the state object.
+            -->
+            cgroup의 state object에 설정할 값을 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+       <term>lxc-cgroup -n foo devices.list</term>
+       <listitem>
+       <para>
+          <!--
+         display the allowed devices to be used.
+          -->
+          허용된 디바이스를 표시한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-cgroup -n foo cpuset.cpus "0,3"</term>
+       <listitem>
+       <para>
+          <!--
+         assign the processors 0 and 3 to the container.
+          -->
+          프로세서 0과 3을 컨테이너에게 할당한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The container is not running.
+            -->
+            컨테이너가 실행중이 아니다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-checkconfig.sgml.in b/doc/ko/lxc-checkconfig.sgml.in
new file mode 100644 (file)
index 0000000..6462e97
--- /dev/null
@@ -0,0 +1,112 @@
+<!--
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-checkconfig</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-checkconfig</refname>
+
+    <refpurpose>
+      <!--
+      check the current kernel for lxc support
+      -->
+      현재 커널의 lxc 지원 여부 검사
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-checkconfig</command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-checkconfig</command> check the current kernel for
+      lxc support
+      -->
+      <command>lxc-checkconfig</command>는 현재 커널이 lxc를 지원하는지 검사한다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-checkconfig</term>
+        <listitem>
+        <para>
+          <!--
+          check the current kernel.
+          CONFIG can be set in the environment to an alternate location.
+          -->
+          현재 커널을 검사한다.
+          CONFIG 환경 변수를 이용하여 다른 위치를 설정할 수 있다.
+          (역주 : 기본값은 /proc/config.gz 이다. Kernel compile option에서 Enable access to .config through /proc/config.gz를 체크하여야 한다)
+        </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-checkpoint.sgml.in b/doc/ko/lxc-checkpoint.sgml.in
new file mode 100644 (file)
index 0000000..a8aebf4
--- /dev/null
@@ -0,0 +1,230 @@
+<!--
+
+(C) Copyright Canonical Ltd. 2014
+
+Authors:
+Tycho Andersen <tycho.andersen@canonical.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-checkpoint</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-checkpoint</refname>
+
+    <refpurpose>
+      <!--
+      checkpoint a container
+      -->
+      컨테이너의 체크포인트 생성 및 복원
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-checkpoint</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="req">-D <replaceable>PATH</replaceable></arg>
+      <arg choice="opt">-r</arg>
+      <arg choice="opt">-s</arg>
+      <arg choice="opt">-v</arg>
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">-F</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-checkpoint</command> checkpoints and restores containers.
+      -->
+      <command>lxc-checkpoint</command> 는 컨테이너의 체크포인트를 생성 및 복원을 수행한다.
+      (역주 : 이 명령어를 사용하기 위해서는 CRIU(Checkpoint/Restore In Userspace)라는 툴이 반드시 필요하다, 컨테이너의 실행상태를 대상으로 한다는 점에서  <command>lxc-snapshot</command>와는 다르다)
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+        <term>
+          <option>-r, --restore</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Restore the checkpoint for the container, instead of dumping it.
+            This option is incompatible with <option>-s</option>.
+            -->
+            컨테이너의 상태를 저장하는 것 대신에 체크포인트로 복원을 수행한다.
+            이 옵션은 <option>-s</option>과 같이 사용될 수 없다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-D <replaceable>PATH</replaceable>, --checkpoint-dir=<replaceable>PATH</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            The directory to dump the checkpoint metadata.
+            -->
+            체크포인트 메타데이터를 저장할 디렉토리를 지정한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-s, --stop</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Optionally stop the container after dumping. This option is
+            incompatible with <option>-r</option>.
+            -->
+            컨테이너의 상태를 저장한 후 컨테이너를 중지한다. 이 옵션은 <option>-r</option>과 같이 사용될 수 없다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-v, --verbose</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Enable verbose criu logging.
+            -->
+            CRIU 로그 기록을 자세하게 한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-d, --daemon</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Restore the container in the background (this is the default).
+            Only available when providing <option>-r</option>.
+            -->
+            컨테이너 복원을 백그라운드에서 수행한다. (이것이 기본으로 되어있다)
+            <option>-r</option> 옵션이랑만 사용가능하다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-F, --foreground</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Restore the container in the foreground. Only available when
+            providing <option>-r</option>.
+            -->
+            컨테이너 복원을 포그라운드에서 수행한다. <option>-r</option> 옵션이랑만 사용가능하다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+
+      <varlistentry>
+        <term>lxc-checkpoint -n foo -D /tmp/checkpoint</term>
+        <listitem>
+          <para>
+            <!--
+            Checkpoint the container foo into the directory /tmp/checkpoint.
+            -->
+            foo 컨테이너의 체크포인트를 /tmp/checkpoint 디렉토리에 생성한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>lxc-checkpoint -r -n foo -D /tmp/checkpoint</term>
+        <listitem>
+          <para>
+            <!--
+            Restore the checkpoint from the directory /tmp/checkpoint.
+            -->
+            foo 컨테이너를 /tmp/checkpoint 디렉토리에 있는 체크포인트로 복원한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Tycho Andersen <email>tycho.andersen@canonical.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-clone.sgml.in b/doc/ko/lxc-clone.sgml.in
new file mode 100644 (file)
index 0000000..b610119
--- /dev/null
@@ -0,0 +1,377 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+Serge Hallyn <serge.hallyn at ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-clone</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-clone</refname>
+
+    <refpurpose>
+      <!--
+      clone a new container from an existing one.
+      -->
+      존재하는 컨테이너를 새로운 컨테이너로 복제
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-clone</command>
+      <arg choice="opt">-s </arg>
+      <arg choice="opt">-K </arg>
+      <arg choice="opt">-M </arg>
+      <arg choice="opt">-H </arg>
+      <arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
+      <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
+      <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
+      <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
+      <arg choice="req">-o <replaceable>orig</replaceable></arg>
+      <arg choice="req">-n <replaceable>new</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-clone</command>
+      <arg choice="opt">-s </arg>
+      <arg choice="opt">-K </arg>
+      <arg choice="opt">-M </arg>
+      <arg choice="opt">-H </arg>
+      <arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
+      <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
+      <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
+      <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
+      <arg choice="req">orig</arg>
+      <arg choice="req">new</arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-clone</command> Creates a new container as a clone of an existing
+      container.  Two types of clones are supported: copy and snapshot.  A copy
+      clone copies the root filessytem from the original container to the new.  A
+      snapshot filesystem uses the backing store's snapshot functionality to create
+      a very small copy-on-write snapshot of the original container.  Snapshot
+      clones require the new container backing store to support snapshotting.  Currently
+      this includes only aufs, btrfs, lvm, overlayfs and zfs.  LVM devices do not support
+      snapshots of snapshots.
+      -->
+      <command>lxc-clone</command>는 존재하는 컨테이너를 복제하여 새로운 컨테이너를 생성한다. 복사, 스냅샷의 두가지 형태의 복제가 지원된다.
+      복사는 원본 컨테이너의 루트 파일시스템을 그대로 새 컨테이너로 복사한다..
+      스냅샷은 저장소의 스냅샷 기능을 이용하여 원본 컨테이너의 copy-on-write 형태로 매우 작은 스냅샷을 생성한다. 스냅샷을 사용하기 위해서는 새 컨테이너의 저장소가 스냅샷 기능을 지원하여야 한다. 현재 스냅샷 기능을 지원하는 것은 aufs, btrfs, lvm, overlayfs, zfs 정도이다. lvm은 스냅샷의 스냅샷은 지원하지 않는다.
+    </para>
+
+    <para>
+      <!--
+      The backing store of the new container will be the same type as the
+      original container, with one exception, overlay containers.
+      aufs and overlayfs snapshots can be created of directory backed
+      containers.  This can be requested by using (for overlayfs) the
+      <replaceable>-B overlayfs</replaceable> arguments.
+      -->
+      오버레이 컨테이너들을 제외하면, 새 컨테이너의 저장소는 원본과 같은 종류를 사용한다.
+      aufs와 overlayfs의 스냅샷은 디렉토리로 구성된 컨테이너로 생성할 수 있다. overlayfs의 경우 <replaceable>-B overlayfs</replaceable> 인수를 통해 이를 지정할 수 있다.
+    </para>
+
+    <para>
+      <!--
+      The names of the original and new container can be given (in that order)
+      after all options, or can be specified with the
+      <replaceable>-o</replaceable> and <replaceable>-n</replaceable> options,
+      respectively.
+      -->
+      원본 컨테이너와 새 컨테이너의 이름은 모든 옵션 뒤에 원본, 새 컨테이너 순으로 지정할 수 있다. 또는 <replaceable>-o</replaceable>과 <replaceable>-n</replaceable> 옵션을 사용하여 지정할 수 있다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-s, --snapshot</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           The new container's rootfs will be a snapshot of the original. This option can be specified when the backing store is LVM, btrfs or zfs, and must be specified when you want to snapshot using aufs or overlayfs.
+              -->
+            새로 생성하는 컨테이너의 루트 파일시스템은 원본의 스냅샷으로 한다. 이 옵션은 저장소가 lvm, btrfs, zfs 일때 지정할 수 있다. 또한 aufs나 overlayfs를 이용한 스냅샷을 원할때만 지정해야 한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-K, --keepname</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Do not change the hostname of the container (in the root
+           filesystem).
+            -->
+            (루트 파일시스템에서) 컨테이너의 호스트 이름을 변경하지 않는다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-M, --keepmac</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Use the same MAC address as the original container, rather than
+           generating a new random one.
+            -->
+            새로 무작위한 주소를 만들지 않고, 원본과 같은 MAC 주소를 사용한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-H, --copyhooks</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Copy all mount hooks into the new container's directory, and
+           update any lxcpaths and container names as needed.
+            -->
+            모든 마운트 훅들을 새 컨테이너의 디렉토리로 복사한다. 그리고 lxcpath와 컨테이너 이름을 필요에 따라 갱신한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-L, --fssize <replaceable>fssize</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           In the case of a block device backed container, a size for the new
+           block device.  By default, the new device will be made the
+           same size as the original.
+            -->
+            블록장치로 구성된 컨테이너의 경우, 새로운 블록 장치의 크기.
+            기본으로 새 디바이스는 원본과 같은 크기로 만들어진다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-p, --lxcpath <replaceable>lxcpath</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           The lxcpath of the original container.  By default, the system
+           wide configured lxcpath will be used.
+            -->
+            원본 컨테이너의 lxcpath. 기본값은 시스템 전역으로 설정되어 잇는 lxcpath를 사용한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-P, --newpath <replaceable>newlxcpath</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           The lxcpath for the new container.  By default the same lxcpath
+           as the original will be used.  Note that with btrfs snapshots,
+           changing lxcpaths may not be possible, as subvolume snapshots
+           must be in the same btrfs filesystem.
+            -->
+            새로 생성될 컨테이너의 lxcpath.
+            기본값은 원본 컨테이너의 lxcpath와 같다.
+            btrfs의 스냅샷의 경우 lxcpath 변경이 불가능 할 수 있음을 주의해야 한다. 왜냐하면 서브볼륨 스냅샷이 같은 btrfs 파일시스템 내에 있어야 하기 때문이다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-B, --backingstore <replaceable>backingstore</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Select a different backing store for the new container.  By
+           default the same as the original container's is used.  Note that
+           currently changing the backingstore is only supported for
+           aufs and overlayfs snapshots of directory backed containers.  Valid
+           backing stores include dir (directory), aufs, btrfs, lvm, zfs, loop
+           and overlayfs.
+            -->
+            새 컨테이너의 저장소를 선택한다.
+            기본 값은 원본 컨테이너가 쓰던 것과 같은 것으로 되어 있다.
+            현재 저장소를 다른 것으로 변경하는 것은 디렉토리로 구성된 컨테이너의 aufs와 overlayfs 스냅샷에서만 지원된다.
+            가능한 값은 dir(디렉토리), aufs, btrfs, lvm zfs, loop 그리고 ovelayfs 이다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-R, --rename</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Rename an existing container.
+            <replaceable>orig</replaceable> is renamed <replaceable>new</replaceable>.
+            -->
+            컨테이너의 이름을 변경한다. <replaceable>orig</replaceable>를 <replaceable>new</replaceable>로 이름을 바꾼다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+
+         <option>-o, --orig <replaceable>orig</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           The name of the original container to clone.
+            -->
+            복제할 원본 컨테이너의 이름.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-n, --new <replaceable>new</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           The name of the new container to create.
+            -->
+            생성할 새 컨테이너의 이름.
+         </para>
+       </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Clone hook</title>
+    <para>
+      <!--
+      If the container being cloned has one or more <filename>lxc.hook.clone</filename>
+      specified, then the specified hooks will be called for the new container.  The
+      first 3 arguments passed to the clone hook will be the container name, a section
+      ('lxc'), and the hook type ('clone').  Extra arguments passed
+      <command>lxc-clone</command> will be passed to the hook program starting at
+      argument 4.  The <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
+      the path under which the container's root filesystem is mounted.  The
+      configuration file pathname is stored in <filename>LXC_CONFIG_FILE</filename>, the
+      new container name in <filename>LXC_NAME</filename>, the old container name in
+      <filename>LXC_SRC_NAME</filename>, and the path or device on which
+      the rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
+      -->
+      만약 복제되는 컨테이너가 1개 이상의 <filename>lxc.hook.clone</filename>을 지정했다면, 지정된 훅은 새 컨테이너가 생성될 때 실행될 것이다.
+      먼저 컨테이너 이름, 섹션('lxc'), 훅 종류('clone') 3개의 인수가 복제 훅에 전달 된다. 그리고 4번째 인수 부터는 <command>lxc-clone</command>로 넘겨줄 수 있다.
+      <filename>LXC_ROOTFS_MOUNT</filename> 환경변수는 컨테이너의 루트 파일시스템이 마운트되어 있는 경로를 넘겨준다.
+      새 컨테이너의 이름은 <filename>LXC_NAME</filename> 변수에, 이전 컨테이너의 이름은 <filename>LXC_SRC_NAME</filename> 환경변수에 담겨 있다. 그리고 루트 파일시스템이 위치하고 있는 곳은 <filename>LXC_ROOTFS_PATH</filename>로 넘겨준다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Notes -->주의</title>
+    <para>
+      <!--
+      <command>lxc-clone</command> is deprecated in favor of
+      <command>lxc-copy</command>.
+      -->
+      <command>lxc-clone</command>는 <command>lxc-copy</command>로 대체되었으며, 제거될 예정이다.
+    </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Serge Hallyn <email>serge.hallyn@ubuntu.com</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-config.sgml.in b/doc/ko/lxc-config.sgml.in
new file mode 100644 (file)
index 0000000..7d309fd
--- /dev/null
@@ -0,0 +1,129 @@
+<!--
+
+lxc-config
+
+(C) Copyright 2014 Canonical Ltd.
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+    <!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+    <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+    <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+    <refmeta>
+        <refentrytitle>lxc-config</refentrytitle>
+        <manvolnum>1</manvolnum>
+    </refmeta>
+
+    <refnamediv>
+        <refname>lxc-config</refname>
+
+        <refpurpose>
+          <!--
+            query LXC system configuration
+            -->
+          LXC 시스템 설정 얻어오기
+        </refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+        <cmdsynopsis>
+            <command>lxc-config</command>
+            <arg choice="opt">-l</arg>
+            <arg choice="opt"><replaceable>item</replaceable></arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1>
+        <title><!-- Description -->설명</title>
+
+        <para>
+          <!--
+            <command>lxc-config</command> queries the lxc system
+            configuration and lets you list all valid keys or query
+            individual keys for their value.
+            -->
+          <command>lxc-config</command>는 lxc 시스템 설정을 보여준다. 가능한 모든 항목의 이름을 나열하기도 하고 각각의 항목들에 설정되어 잇는 값을 보여주기도 한다.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title><!-- Options -->옵션</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-l</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        List all supported keys.
+                        -->
+                      지원되는 모든 항목의 이름을 나열한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>item</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                        Query the value of the specified key.
+                        -->
+                      지정한 항목에 설정되어 있는 값을 표시한다.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    &seealso;
+
+    <refsect1>
+        <title><!--Author-->저자</title>
+        <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+    </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-console.sgml.in b/doc/ko/lxc-console.sgml.in
new file mode 100644 (file)
index 0000000..fd6820a
--- /dev/null
@@ -0,0 +1,208 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-console</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-console</refname>
+
+    <refpurpose>
+      <!--
+      Launch a console for the specified container
+      -->
+      지정한 컨테이너의 콘솔 실행
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-console</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-e <replaceable>escape character</replaceable></arg>
+      <arg choice="opt">-t <replaceable>ttynum</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      If the tty service has been configured and is available for the
+      container specified as parameter, this command will launch a
+      console allowing to log on the container.
+      -->
+      만약 파라미터로 지정한 컨테이너의 tty 서비스가 제대로 설정되어 있고 사용가능한 상태라면, 이 명령어는 컨테이너에 로그인 할 수 있는 콘솔을 실행한다.
+    </para>
+
+    <para>
+      <!--
+      The available tty are free slots taken by this command. That
+      means if the container has four ttys available and the command
+      has been launched four times each taking a different tty, the
+      fifth command will fail because no console will be available.
+      -->
+      사용가능한 tty는 이 명령어로 얻어올 수 있는 빈 슬롯을 의미한다.
+      즉, 만약 컨테이너가 4개의 tty가 사용가능하고 명령어가 4번 실행하여 각각 다른 tty를 얻어왔다면, 다섯번째 명령은 실패할 것이다. 왜냐하면 가능한 콘솔이 없기 때문이다.
+    </para>
+
+    <para>
+      <!--
+      The command will connect to a tty. If the connection is lost or
+      broken, the command can be launched again and regain the tty at
+      the state it was before the disconnection.
+      -->
+      명령어는 tty에 연결한다. 연결이 끊어지면, 명령어는 다시 실행되어 연결 끊기기 이전 상태에서 tty를 얻어오려고 시도한다.
+    </para>
+
+    <para>
+      <!--
+      A <replaceable>ttynum</replaceable> of 0 may be given to attach
+      to the container's /dev/console instead of its
+      dev/tty&lt;<replaceable>ttynum</replaceable>&gt;.
+      -->
+      <replaceable>ttynum</replaceable>가 0으로 지정되어 있으면, 컨테이너의 /dev/console에 연결한다. 그렇지 않으면 dev/tty&lt;<replaceable>ttynum</replaceable>&gt;에 연결한다.
+    </para>
+
+    <para>
+      <!--
+      A keyboard escape sequence may be used to disconnect from the tty
+      and quit lxc-console. The default escape sequence is &lt;Ctrl+a q&gt;.
+      -->
+      tty 접속을 끊고 lxc-console을 나가고 싶다면 키보드 이스케이프 키를 이용하면 된다. 기본키는 &lt;Ctrl+a q&gt;이다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-e, --escape <replaceable>escape character</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the escape sequence prefix to use instead of
+            &lt;Ctrl a&gt;.
+            This may be given as '^letter' or just 'letter'. For example
+            to use &lt;Ctrl+b q&gt; as the escape sequence use -e '^b'.
+            -->
+            &lt;Ctrl a&gt; 대신에 사용할 이스케이프 키 prefix를 지정한다.
+            '^문자' 또는 '문자'로 지정 가능하다.
+            예를 들어 &lt;Ctrl+b q&gt;를 사용하고 싶다면, -e '^b'와 같이 지정하면 된다.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+         <option>-t, --tty <replaceable>ttynum</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+            Specify the tty number to connect to or 0 for the console. If not
+           specified the next available tty number will be automatically
+           chosen by the container.
+            -->
+            연결하고자 하는 tty의 번호 또는 콘솔 연결을 위해 0을 지정한다.
+            지정하지 않으면, 다음으로 사용가능한 tty 번호를 컨테이너가 자동으로 선택한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>tty service denied</term>
+        <listitem>
+          <para>
+            <!--
+           No tty is available or there is not enough privilege to
+           use the console. For example, the container belongs to
+           user "foo" and "bar" is trying to open a console to it.
+            -->
+            사용가능한 tty가 없거나 콘솔을 사용하기에 충분한 privilege가 없다.
+            예를 들면, 컨테이너가 "foo" 사용자 소유인데 "bar"가 콘솔을 열려고 하는 경우이다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-copy.sgml.in b/doc/ko/lxc-copy.sgml.in
new file mode 100644 (file)
index 0000000..40b3dba
--- /dev/null
@@ -0,0 +1,392 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Inc. 2007, 2008
+
+Authors:
+Christian Brauner <christian.brauner at mailbox.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-copy</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-copy</refname>
+
+    <refpurpose>
+      <!--
+      copy an existing container.
+      -->
+      존재하는 컨테이너 복사
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-e, --ephemeral</arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-R, --rename</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-copy</command> creates and optionally starts (ephemeral or
+      non-ephemeral) copies of existing containers. It replaces
+      <command>lxc-clone</command> and <command>lxc-start-ephemeral</command>.
+      -->
+      <command>lxc-copy</command>는 존재하는 컨테이너의 (임시적 또는 영구적) 복사본을 생성하고, 옵션에 따라 시작하기도 한다. <command>lxc-clone</command>와 <command>lxc-start-ephemeral</command>를 대체한다.
+    </para>
+    <para>
+      <!--
+      <command>lxc-copy</command> creates copies of existing containers. Copies
+      can be complete clones of the original container. In this case the whole
+      root filesystem of the container is simply copied to the new container. Or
+      they can be snapshots, i.e. small copy-on-write copies of the original
+      container. In this case the specified backing storage for the copy must
+      support snapshots. This currently includes aufs, btrfs, lvm (lvm devices
+      do not support snapshots of snapshots.), overlay, and zfs.
+      -->
+      <command>lxc-copy</command>는 존재하는 컨테이너의 복사본을 생성한다. 복사본은 원본 컨테이너를 말그대로 복사한 것일 수 있다. 이 경우 컨테이너의 전체 루트 파일시스템은 단순히 새로운 컨테이너로 복사된다.
+      또는, 원본 컨테이너를 copy-on-write한 것과 같이 스냅샷이 될 수 있다. 이 경우 복사본을 위해 지정한 저장소는 스냅샷을 지원하여야 한다. 이러한 저장소에는 현재 aufs, btrfs, lvm (lvm 장치는 스냅샷의 스냅샷은 지원하지 않음), overlay, zfs가 있다.
+    </para>
+      
+    <para>
+    <!--
+    The copy's backing storage will be of the same type as the original
+    container. aufs or overlayfs snapshots of directory backed containers are
+    exempted from this rule.
+    -->
+    복사본의 저장소는 원본 컨테이너와 같은 종류가 된다. 단, aufs나 디렉토리로 구성된 컨테이너의 overayfs 스냅샷은 예외이다.
+    </para>
+
+    <para>
+    <!--
+    When the <replaceable>-e</replaceable> flag is specified an ephemeral
+    snapshot of the original container is created and started. Ephemeral
+    containers will have <command>lxc.ephemeral = 1</command> set in their
+    config file and will be destroyed on shutdown. When
+    <replaceable>-e</replaceable> is used in combination with
+    <replaceable>-D</replaceable> a non-ephemeral snapshot of the original
+    container is created and started.
+    -->
+    <replaceable>-e</replaceable>가 지정되면, 원본 컨테이너의 임시 스냅샷이 생성되고 시작된다. 임시 컨테이너는 자신의 설정파일 안에 <command>lxc.ephemeral = 1</command>를 가지게 되며, 종료시에 제거된다. <replaceable>-e</replaceable>와 함께 <replaceable>-D</replaceable>를 같이 지정하면 원본 컨테이너의 영구적인 스냅샷이 생성되고 실행된다.
+    </para>
+
+    <para>
+    <!--
+    When <replaceable>-e</replaceable> is specified and no newname is given via
+    <replaceable>-N</replaceable> a random name for the snapshot will be chosen.
+    -->
+    <replaceable>-e</replaceable>는 지정하고 <replaceable>-N</replaceable>으로 새이름을 지정하지 않으면, 무작위로 이름을 정한다.
+    </para>
+
+    <para>
+    <!--
+    Containers created and started with <replaceable>-e</replaceable> can have
+    custom mounts. These are specified with the <replaceable>-m</replaceable>
+    flag. Currently three types of mounts are supported:
+    <replaceable>aufs</replaceable>, <replaceable>bind</replaceable>, and
+    <replaceable>overlay</replaceable>. Mount types are specified as suboptions
+    to the <replaceable>-m</replaceable> flag and can be specified multiple
+    times separated by commas. <replaceable>aufs</replaceable> and
+    <replaceable>overlay</replaceable> mounts are currently specified in the
+    format <replaceable>-m overlay=/src:/dest</replaceable>.  When no
+    destination <replaceable>dest</replaceable> is specified
+    <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. Read-only <replaceable>bind</replaceable>
+    mounts are specified <replaceable>-m bind=/src:/dest:ro</replaceable> and
+    read-write <replaceable>bind</replaceable> mounts <replaceable>-m
+    bind=/src:/dest:rw</replaceable>. Read-write <replaceable>bind</replaceable>
+    mounts are the default and <replaceable>rw</replaceable> can be missing when
+    a read-write mount is wanted. When <replaceable>dest</replaceable> is
+    missing <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. An example for multiple mounts would be
+    <replaceable>-m
+    bind=/src1:/dest1:ro,bind=/src2:ro,overlay=/src3:/dest3</replaceable>.
+    -->
+    <replaceable>-e</replaceable>로 생성되고 실행되는 컨테이너들은 자신만의 마운트를 가질 수 있다. 이는 <replaceable>-m</replaceable>으로 지정된다. 현재 지원하는 마운트의 형식은 <replaceable>aufs</replaceable>, <replaceable>bind</replaceable>, <replaceable>overlay</replaceable>의 세 종류이다. 마운트 형식은 <replaceable>-m</replaceable>의 추가 인수로 지정된다. 그리고 쉼표(,)로 구분하여 여러번 지정할 수 있다. <replaceable>aufs</replaceable>와 <replaceable>overlay</replaceable> 마운트는 현재 <replaceable>-m overlay=/src:/dest</replaceable>와 같이 지정한다. <replaceable>dest</replaceable>의 대상이 지정되지 않았다면 <replaceable>dest</replaceable>는 <replaceable>src</replaceable>와 동일한 값을 가진다.
+    읽기 전용 <replaceable>bind</replaceable> 마운트는 <replaceable>-m bind=/src:/dest:ro</replaceable>로 읽기쓰기 가능 <replaceable>bind</replaceable>마운트는 <replaceable>-m bind=/src:/dest:rw</replaceable>로 지정한다. 읽기쓰기 가능 <replaceable>bind</replaceable> 마운트가 기본값이므로, 읽기쓰기 가능을 원한다면 <replaceable>rw</replaceable>은 빼도 무관하다. <replaceable>dest</replaceable>를 생략했다면 마찬가지로 <replaceable>dest</replaceable>는 <replaceable>src</replaceable>와 같다. 여러번 마운트는 <replaceable>-m bind=/src1:/dest1:ro,bind=/src2:ro,overlay=/src3:/dest3</replaceable>와 같이 가능하다.
+    </para>
+
+    <para>
+    <!--
+    The mounts, their options, and formats supported via the
+    <replaceable>-m</replaceable> flag are subject to change.
+    -->
+    <replaceable>-m</replaceable>를 통해 지원되는 마운트, 옵션, 형식은 변경될 수 있다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+         <varlistentry>
+           <term> <option>-N,--newname <replaceable>newname</replaceable></option> </term>
+          <listitem>
+           <para><!-- The name for the copy. -->복사본의 이름</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-p,--newpath <replaceable>newpath</replaceable></option> </term>
+          <listitem>
+           <para><!-- The path for the copy. -->복사본의 경로</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-R,--rename </option> </term>
+          <listitem>
+           <para><!-- Rename the original container. -->원본 컨테이너의 이름 변경</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-s,--snapshot </option> </term>
+          <listitem>
+            <para>
+            <!--
+            Create a snapshot of the original container. The backing
+            storage for the copy must support snapshots. This currently includes
+            aufs, btrfs, lvm, overlay, and zfs.
+            -->
+            원본 컨테이너의 스냅샷을 생성한다. 복사본의 저장소는 반드시 스냅샷을 지원해야 한다. 현재 aufs, btrfs, lvm, overlay, zfs가 가능하다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-F,--foreground</option> </term>
+          <listitem>
+            <para>
+            <!--
+            Run the snapshot in the foreground. The snapshots console will
+            be attached to the current tty. (This option can only be specified
+            in conjunction with <replaceable>-e</replaceable>.)
+            -->
+            스냅샷을 포그라운드로 실행한다. 스냅샷 콘솔은 현재 tty에 붙게 된다. (이 옵션은 <replaceable>-e</replaceable> 옵션이랑만 사용 가능하다.)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-d, --daemon</option> </term>
+          <listitem>
+            <para>
+            <!--
+            Run the snapshot as a daemon (This is the default mode for
+            ephemeral containers.). As the container has no more tty, if an
+            error occurs nothing will be displayed, the log file can
+            be used to check the error. (This option can only be specified in
+            conjunction with <replaceable>-e</replaceable>.)
+            -->
+            데몬으로 스냅샷을 실행한다. (이는 임시 컨테이너의 기본 모드이다.) 오류가 발생하더라도 컨테이너가 tty를 가지지 않기 때문에 오류는 표시되지 않는다.
+            대신 로그 파일을 사용해 로그를 확인할 수 있다. 이 옵션은 <replaceable>-e</replaceable> 옵션이랑만 사용 가능하다.)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-m, --mount <replaceable>mounttype</replaceable></option> </term>
+          <listitem>
+            <para>
+            <!--
+            Specify a mount for a snapshot  The
+            <replaceable>opts</replaceable> argument for the mount type can by
+            of type {aufs, bind, overlay}. For example <option>-m
+            bind=/src:/dest:ro,overlay=/src:/dest</option> (This option can
+            currently only be specified in conjunction with
+            <replaceable>-e</replaceable>.).
+            -->
+            스냅샷의 마운트를 지정한다. 마운트 형식을 위한 <replaceable>opts</replaceable> 인자는 aufs, bind, overlay를 사용 가능하다. 예를 들면 <option>-m bind=/src:/dest:ro,overlay=/src:/dest</option>이다. 이 옵션은 <replaceable>-e</replaceable> 옵션이랑만 사용 가능하다.)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-B, --backingstorage <replaceable>backingstorage</replaceable></option></term>
+          <listitem>
+            <para>
+            <!--
+            Specify the backing storage type to be used for the copy
+            where 'backingstorage' is of type 'aufs', 'btrfs', 'dir', 'lvm', 'loop',
+            'overlay', or 'zfs'.
+            -->
+            복사본이 사용할 저장소의 형식을 지정한다. 'backingstorage'에는 'aufs', 'btrfs', 'dir', 'lvm', 'loop', 'overlay','zfs'이 사용 가능하다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-L, --fssize <replaceable>size [unit]</replaceable></option></term>
+          <listitem>
+            <para><!-- Specify the size for an 'lvm' filesystem. -->
+            'lvm' 파일시스템의 크기를 지정한다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-D, --keepdata </option></term>
+          <listitem>
+            <para>
+            <!--
+            When this option is specified with
+            <replaceable>-e</replaceable> a non-ephemeral container is created
+            and started.-->
+            이 옵션을 <replaceable>-e</replaceable>와 지정하면 영구적인 컨테이너가 생성되고 시작된다.
+            </para>
+           </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-K, --keepname </option></term>
+          <listitem>
+            <para>
+            <!--
+            When this option is specified the hostname of the original
+            container will be kept for the copy.
+            -->
+            이 옵션이 지정되면 원본 컨테이너의 호스트이름이 복사본에서도 그대로 유지된다.
+            </para>
+           </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-M, --keepmac </option></term>
+          <listitem>
+            <para>
+            <!--
+            When this option is specified the MAC address of the original
+            container will be kept for the copy.
+            -->
+            이 옵션이 지정되면 원본 컨테이너의 MAC 주소가 복사본에서도 그대로 유지된다.
+            </para>
+           </listitem>
+         </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Copy hook -->복사 훅</title>
+    <para>
+      <!--
+      If the container being copied has one or more
+      <filename>lxc.hook.clone</filename> specified, then the specified hooks
+      will be called for the new container. The first 3 arguments passed to the
+      clone hook will be the container name, a section ('lxc'), and the hook
+      type ('clone'). Extra arguments passed to <command>lxc-copy</command> will
+      be passed to the hook program starting at argument 4. The
+      <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
+      the path under which the container's root filesystem is mounted. The
+      configuration file pathname is stored in
+      <filename>LXC_CONFIG_FILE</filename>, the new container name in
+      <filename>LXC_NAME</filename>, the old container name in
+      <filename>LXC_SRC_NAME</filename>, and the path or device on which the
+      rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
+      -->
+      복사되는 컨테이너에 <filename>lxc.hook.clone</filename>가 하나 이상 지정되어 있다면, 지정한 훅들은 새로운 컨테이너를 위해 실핼될 것이다.
+      clone 훅에게 넘겨지는 처음 3개 인자들은 컨테이너 이름, 섹션 ('lxc'), 훅의 종류 ('clone')이 될 것이다.
+      <command>lxc-copy</command>에 넘겨지는 추가 인자들은 훅 프로그램에 4번째 인자부터 넘겨지기 시작한다.
+      <filename>LXC_ROOTFS_MOUNT</filename> 환경 변수는 컨테이너의 루트 파일시스템이 마운트되어 있는 경로를 담고 있다.
+      설정 파일의 경로 이름은 <filename>LXC_CONFIG_FILE</filename>에, 새 컨테이너의 이름은 <filename>LXC_NAME</filename>에, 원본 컨테이너의 이름은 <filename>LXC_SRC_NAME</filename>에, 그리고 루트 파일시스템이 위치하고 있는 경로나 디바이스는 <filename>LXC_ROOTFS_PATH</filename>에 각각 담겨 있다.
+    </para>
+  </refsect1>
+
+  &commonoptions;
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Christian Brauner <email>christian.brauner@mailbox.org</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-create.sgml.in b/doc/ko/lxc-create.sgml.in
new file mode 100644 (file)
index 0000000..ed685a4
--- /dev/null
@@ -0,0 +1,296 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-create</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-create</refname>
+
+    <refpurpose>
+      <!--
+      creates a container
+      -->
+      컨테이너 생성
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-create</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
+      <arg choice="req">-t <replaceable>template</replaceable></arg>
+      <arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
+      <arg choice="opt">-- <replaceable>template-options</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-create</command> creates a system object where is
+      stored the configuration information and where can be stored
+      user information. The identifier <replaceable>name</replaceable>
+      is used to specify the container to be used with the different
+      lxc commands.
+      -->
+      <command>lxc-create</command>는 설정정보와 사용자 정보가 저장되는 시스템 객체를 생성한다.
+      <replaceable>name</replaceable>은  다른 lxc 명령어들에서 특정 컨테이너를 지정하는데 사용된다.
+    </para>
+    <para>
+      <!--
+      The object is a directory created in <filename>@LXCPATH@</filename>
+      and identified by its name.
+      -->
+      객체는 <filename>@LXCPATH@</filename>에 작성되는 디렉토리이며, 자신의 <replaceable>name</replaceable>으로 구분되어 진다.
+    </para>
+
+    <para>
+      <!--
+      The object is the definition of the different resources an
+      application can use or can see. The more the configuration file
+      contains information, the more the container is isolated and
+      the more the application is jailed.
+      -->
+      객체는 응용 프로그램이 사용할 수 있고 볼 수 있는 여러 자원들의 정의이다.
+      설정파일이 많은 정보를 담고 있을수록 컨테이너는 더욱더 고립될 수 있고, 응용 프로그램은 더욱더 격리될 수 있다.
+    </para>
+
+    <para>
+      <!--
+      If the configuration file <replaceable>config_file</replaceable>
+      is not specified, the container will be created with the default
+      isolation: processes, sysv ipc and mount points.
+      -->
+      만약 설정파일 <replaceable>config_file</replaceable>가 지정되지 않았다면, 컨테이너는 프로세스, sysv ipc, 마운트 포인트에 대한 기본적인 고립 상태로 만들어진다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-f, --config <replaceable>config_file</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the configuration file to configure the virtualization
+           and isolation functionalities for the container.
+            -->
+            컨테이너 가상화 및 고립 기능을 설정하는 설정파일을 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-t, --template <replaceable>template</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           <!--
+            'template' is the short name of an existing 'lxc-template'
+           script that is called by lxc-create,
+           eg. busybox, debian, fedora, ubuntu or sshd.
+           Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename>
+           for details of the expected script structure.
+           Alternatively, the full path to an executable template script
+           can also be passed as a parameter.
+           "none" can be used to force lxc-create to skip rootfs creation.
+            -->
+            lxc-create 명령어는 'lxc-template' 스크립트를 호출한다. <replaceable>template</replaceable>은 'lxc-template' 스크립트의 짧은 이름으로, busybox, debian, fedora, ubuntu, sshd 등이 있다. 스크립트의 구조에 대해 궁금할 때는  <filename>@LXCTEMPLATEDIR@</filename>에 있는 예제들을 참고하면 된다.
+           <replaceable>template</replaceable> 대신 스크립트의 전체 경로를 지정할 수도 있다.
+           "none"으로 지정하면 루트파일시스템 생성을 강제로 건너뛸 수 있다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-B, --bdev <replaceable>backingstore</replaceable></option>
+       </term>
+       <listitem>
+          <para>
+            <!--
+           'backingstore' is one of 'dir', 'lvm', 'loop', 'btrfs', 'zfs', 'rbd', or 'best'.  The
+           default is 'dir', meaning that the container root filesystem
+           will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
+           This backing store type allows the optional
+           <replaceable>&#045;&#045;dir ROOTFS</replaceable> to be specified, meaning
+           that the container rootfs should be placed under the specified path,
+           rather than the default.  (The 'none' backingstore type is an alias for
+           'dir'.)  If 'btrfs' is specified, then the
+           target filesystem must be btrfs, and the container rootfs will be
+           created as a new subvolume.  This allows snapshotted clones to be
+           created, but also causes rsync &#045;&#045;one-filesystem to treat it as a
+           separate filesystem.
+           If backingstore is 'lvm', then an lvm block device will be
+           used and the following further options are available:
+            <replaceable>&#045;&#045;lvname lvname1</replaceable> will create an LV
+           named <filename>lvname1</filename> rather than the default, which
+           is the container name.  <replaceable>&#045;&#045;vgname vgname1</replaceable>
+           will create the LV in volume group <filename>vgname1</filename>
+           rather than the default, <filename>lxc</filename>.
+           <replaceable>&#045;&#045;thinpool thinpool1</replaceable> will create the
+           LV as a thin-provisioned volume in the pool named
+           <filename>thinpool1</filename> rather than the
+           default, <filename>lxc</filename>.
+           <replaceable>&#045;&#045;fstype FSTYPE</replaceable> will create an FSTYPE
+           filesystem on the LV, rather than the default, which is ext4.
+           <replaceable>&#045;&#045;fssize SIZE</replaceable> will create a LV (and
+           filesystem) of size SIZE rather than the default, which is 1G.
+            -->
+            'backingstore'는 'dir', 'lvm', 'loop', 'btrfs', 'zfs', 'rbd', 'best'를 지정할 수 있다.
+            기본 값은 'dir'로 컨테이너 루트 파일시스템을 의미하며 <filename>@LXCPATH@/container/rootfs</filename>이하 디렉토리를 가리킨다.
+            'dir'은 옵션으로 컨테이너 루트 파일시스템이 어느 경로에 위치할지 지정할 수 있으며, <replaceable>&#045;&#045;dir ROOTFS</replaceable>로 가능하다.
+            ('none'은 'dir'과 동일하다)
+            'btrfs'가 지정되어 있다면, 타겍 파일시스템은 반드시 btrfs여야 한다. 그리고 컨테이너 루트 파일시스템은 새로운 서브볼륨으로 생성된다. 이는 스냅샷된 복제물을 만들지만, rsync &#045;&#045;one-filesystem는 분리된 파일시스템으로 취급하게 된다.
+            'lvm'으로 지정되있다면, lvm 블록 디바이스가 사용되며, 이때 사용가능한 옵션은 다음과 같다 : <replaceable>&#045;&#045;lvname lvname1</replaceable>는 이름이 <filename>lvname1</filename>인 LV를 만든다(기본값은 컨테이너 이름).
+<replaceable>&#045;&#045;vgname vgname1</replaceable>는 이름이 <filename>vgname1</filename>인 볼륨그룹 안에 LV를 만든다(기본값은 <filename>lxc</filename>).
+            <replaceable>&#045;&#045;thinpool thinpool1</replaceable>는 <filename>thinpool1</filename>라는 풀 안에 있는 thin-provisioned 볼륨으로 LV를 만든다(기본값은  <filename>lxc</filename>).
+            <replaceable>--fstype FSTYPE</replaceable>는 LV의 파일시스템을 FSTYPE으로 지정한다(기본값은 ext4).
+            <replaceable>--fssize SIZE</replaceable>는 LV의 크기를 지정한다(기본값은 1G).
+         </para>
+         <para>
+           <!--
+           If backingstore is 'loop', you can use <replaceable>&#045;&#045;fstype FSTYPE</replaceable> and <replaceable>&#045;&#045;fssize SIZE</replaceable> as 'lvm'. The default values for these options are the same as 'lvm'.
+           -->
+            'loop'로 지정되어 있다면, 'lvm'과 비슷하게 <replaceable>--fstype FSTYPE</replaceable>과 <replaceable>--fssize SIZE</replaceable>를 사용할 수 있다(기본값은 'lvm'과 동일).
+         </para>
+         <para>
+           <!--
+           If backingstore is 'rbd', then you will need to have a valid configuration in <filename>ceph.conf</filename> and a <filename>ceph.client.admin.keyring</filename> defined.
+           You can specify the following options :
+           <replaceable>&#045;&#045;rbdname RBDNAME</replaceable> will create a blockdevice named RBDNAME rather than the default, which is the container name.
+           <replaceable>&#045;&#045;rbdpool POOL</replaceable> will create the blockdevice in the pool named POOL, rather than the default, which is 'lxc'.
+           -->
+           'rbd'로 지정되어 있다면, <filename>ceph.conf</filename>내 적절하게 설정사항이 있어야 하고 <filename>ceph.client.admin.keyring</filename>가 정의되어 있어야 한다.
+           아래 옵션을 지정할 수 있다 :
+           <replaceable>&#045;&#045;rbdname RBDNAME</replaceable>는 생성하는 블록 장치의 이름을 RBDNAME로 지정한다(기본값은 컨테이너의 이름).
+           <replaceable>&#045;&#045;rbdpool POOL</replaceable>는 블록 장치를 넣을 풀을 POOL로 지정한다(기본값은 'lxc').
+         </para>
+         <para>
+            <!--
+           If backingstore is 'best', then lxc will try, in order, btrfs,
+           zfs, lvm, and finally a directory backing store.
+            -->
+            'best'로 지정되어 있다면, lxc는 btrfs, zfs, lvm, dir의 순서대로 시도해본다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-- <replaceable>template-options</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           This will pass <replaceable>template-options</replaceable> to the
+           template as arguments.  To see the list of options supported by
+           the template, you can run
+           <command>lxc-create -t TEMPLATE -h</command>.
+            -->
+            이것은 <replaceable>template-options</replaceable>를 템플릿에게 인수로 넘긴다. 만약 어떤 인수를 템플릿에서 지원하는지 보고 싶다면, <command>lxc-create -t TEMPLATE -h</command>를 사용하면 된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container already exists</term>
+        <listitem>
+          <para>
+            <!--
+           As the message mention it, you try to create a container
+           but there is a container with the same name. You can use
+           the <command>lxc-ls</command> command to list the
+           available containers on the system.
+            -->
+            메시지에 나와있는 대로, 이미 같은 이름의 컨테이너가 존재하는 경우이다. <command>lxc-ls</command> 명령어를 사용하여 시스템에 이미 존재하는 컨테이너를 확인해볼 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-destroy.sgml.in b/doc/ko/lxc-destroy.sgml.in
new file mode 100644 (file)
index 0000000..5a9cb36
--- /dev/null
@@ -0,0 +1,165 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-destroy</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-destroy</refname>
+
+    <refpurpose>
+      <!--
+      destroy a container.
+      -->
+      컨테이너 제거
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-destroy</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-f</arg>
+      <arg choice="opt">-s</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!--Description-->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-destroy</command> destroys the system object
+      previously created by the <command>lxc-create</command> command.
+      -->
+      <command>lxc-destroy</command>는 <command>lxc-create</command>로 이전에 생성했던 시스템 객체를 제거한다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+      <varlistentry>
+       <term>
+         <option>-f, --force</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           If a container is running, stop it first.  If this option is
+           not specified and the container is running, then
+           <command>lxc-destroy</command> will be aborted.
+            -->
+            만약 컨테이너가 실행중이라면, 컨테이너를 종료시킨다.
+            이 옵션이 지정되지 않았을 때 컨테이너가 실행중이라면, <command>lxc-destroy</command>는 중지될 것이다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-s, --snapshots</option></term>
+        <listitem>
+         <para>
+            <!--
+           destroy the specified container including all its snapshots.
+            -->
+            해당 컨테이너의 모든 스냅샷까지 제거한다.
+         </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container for destruction was not found. It
+           is probable it does not exists and was already
+           destroyed.You can use the <command>lxc-ls</command>
+           command to list the available containers on the system.
+            -->
+            제거하려는 컨테이너를 찾을 수 없는 경우이다. 아마도 존재하지 않았거나 이미 제거되었을 경우일 것이다. <command>lxc-ls</command> 명령어를 사용하여 시스템에 존재하는 컨테이너를 확인해볼 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-device.sgml.in b/doc/ko/lxc-device.sgml.in
new file mode 100644 (file)
index 0000000..b2c5cf4
--- /dev/null
@@ -0,0 +1,203 @@
+
+<!--
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-device</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-device</refname>
+
+    <refpurpose>
+      <!--
+      manage devices of running containers
+      -->
+      실행 중인 컨테이너의 디바이스 관리
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-device</command>
+      <arg choice="opt">-h</arg>
+      <arg choice="opt">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">add</arg>
+      <arg choice="opt">DEVICE</arg>
+      <arg choice="opt">NAME</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-device</command> manages devices in running container.
+      -->
+      <command>lxc-device</command>는 실행중인 컨테이너의 디바이스를 관리한다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+      <varlistentry>
+        <term>
+          <option>-h</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            The full command help message.
+            -->
+            명령어의 전체 도움말을 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-n, --name=<replaceable>NAME</replaceable></option></term>
+        <listitem>
+          <para>
+            <!--
+             The name of the target container.
+             -->
+            대상으로 하는 컨테이너의 이름.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>action</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            What action to perform. Only 'add' is supported at this point.
+            -->
+            수행할 동작. 현재는 'add'만 지원된다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>DEVICE</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            The device to add to the container.
+            It can either be the path to a device under /dev or a network
+            interface name.
+            -->
+            컨테이너에 추가할 디바이스.
+            장치의 경로를 /dev 밑으로 지정하거나 네트워크 인터페이스 이름이 지정 가능하다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option><optional>NAME</optional></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Name for the device within the container.
+            -->
+            컨테이너 내부에서 쓰일 디바이스의 이름
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-device -n p1 add /dev/video0</term>
+        <listitem>
+        <para>
+          <!--
+          Creates a /dev/video0 device in container p1 based on the matching
+          device on the host.
+          -->
+          컨테이너 p1 내부에 호스트의 것과 같은 /dev/video0 장치를 생성한다.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>lxc-device -n p1 add eth0 eth1</term>
+        <listitem>
+        <para>
+          <!--
+           Moves eth0 from the host as eth1 in p1.
+           -->
+          호스트의 eth0를 컨테이너 p1에 eth1의 이름으로 옮긴다.
+        </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-execute.sgml.in b/doc/ko/lxc-execute.sgml.in
new file mode 100644 (file)
index 0000000..e7dc794
--- /dev/null
@@ -0,0 +1,238 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-execute</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-execute</refname>
+
+    <refpurpose>
+      <!--
+      run an application inside a container.
+      -->
+      컨테이너 내부로 응용 프로그램 실행
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-execute</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
+      <arg choice="opt">-s KEY=VAL</arg>
+      <arg choice="opt">-- <replaceable>command</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-execute</command> runs the specified
+      <replaceable>command</replaceable> inside the container
+      specified by <replaceable>name</replaceable>.
+      -->
+      <command>lxc-execute</command>는 지정한 <replaceable>command</replaceable>를 <replaceable>name</replaceable>라는 이름의 컨테이너 내부에서 실행한다.
+    </para>
+    <para>
+      <!--
+      It will setup the container
+      according to the configuration previously defined with the
+      lxc-create command or with the configuration file parameter.
+      If no configuration is
+      defined, the default isolation is used.
+      -->
+      이 명령어는 <command>lxc-create</command> 정의했던 설정을 토대로 또는 인수
+를 통해 넘긴 설정파일을 토대로 컨테이너를 세팅한다.
+      만약 정의된 설정이 없다면, 기본 고립 환경을 사용한다.
+    </para>
+    <para>
+      <!--
+      This command is mainly used when you want to quickly launch an
+      application in an isolated environment.
+      -->
+      이 명령어들은 고립된 환경에서 응용 프로그램을 빠르게 실행해보고 싶을 때, 주로 사용한다.
+    </para>
+    <para>
+      <!--
+      <command>lxc-execute</command> command will run the
+      specified command into the container via an intermediate
+      process, <command>lxc-init</command>.
+      This lxc-init after launching  the specified command,
+      will wait for its end and all other reparented processes.
+      (to support daemons in the container).
+      In other words, in the
+      container, <command>lxc-init</command> has the pid 1 and the
+      first process of the application has the pid 2.
+      -->
+      <command>lxc-execute</command>명령어는 컨테이너 내부에서 <command>lxc-init</command> 프로세스를 통해 지정한 명령어를 실행한다.
+      <command>lxc-init</command>은 지정한 명령어를 실행한 뒤에, 해당 명령어 및 그 명령어에서 실행된 모든 프로세스들을 기다린다(컨테이너 내에서 데몬을 지원하기 위한 것).
+      즉, 컨테이너내에서 <command>lxc-init</command>는 pid는 1이 되고, 그 다음으로 실행되는 응용 프로그램은 pid가 2가 된다.
+     </para>
+     <para>
+       <!--
+      The above <command>lxc-init</command> is designed to forward received
+      signals to the started command.
+       -->
+       <command>lxc-init</command>는 시그널들을 받아서 시작한 명령어에게 보내주도록 되어 있다.
+     </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-f, --rcfile <replaceable>config_file</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the configuration file to configure the virtualization
+           and isolation functionalities for the container.
+            -->
+            컨테이너의 가상화나 고립 기능을 설정할 때 쓰일 설정파일을 지정한다.
+         </para>
+         <para>
+            <!--
+          This configuration file if present will be used even if there is
+          already a configuration file present in the previously created
+          container (via lxc-create).
+            -->
+            지정한 설정파일이 존재한다면, 이전에 생성된(lxc-create를 통해) 컨테이너에 설정파일이 이미 존재한다고 하더라도 지정한 설정파일을 사용한다.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+         <option>-s, --define <replaceable>KEY=VAL</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Assign value <replaceable>VAL</replaceable> to configuration
+           variable <replaceable>KEY</replaceable>. This overrides any
+           assignment done in <replaceable>config_file</replaceable>.
+            -->
+            <replaceable>VAL</replaceable> 값을 <replaceable>KEY</replaceable> 설정변수에 넣는다.
+            이는 <replaceable>config_file</replaceable>에서의 설정을 덮어쓴다.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--</option></term>
+       <listitem>
+         <para>
+            <!--
+           Signal the end of options and disables further option
+           processing. Any arguments after the &#045;&#045; are treated as
+           arguments to <replaceable>command</replaceable>.
+            -->
+            옵션이 끝임을 지정하고 더이상 옵션에 대한 처리를 하지 않는다.
+            &#045;&#045; 이후에 오는 모든 인수는 <replaceable>command</replaceable>의 인수로서 처리된다.
+         </para>
+         <para>
+            <!--
+           This option is useful when you want specify options
+           to <replaceable>command</replaceable> and don't want
+           <command>lxc-execute</command> to interpret them.
+            -->
+            이것은 <replaceable>command</replaceable>에게 옵션을 지정하고, <command>lxc-execute</command>가 그 옵션을 처리하지 않게 하는데 유용하게 사용된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container is busy</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container is already running an
+           application. You should stop it before reuse this
+           container or create a new one.
+            -->
+            지정한 컨테이너가 이미 실행중인 경우이다. 컨테이너를 사용하고 싶다면 컨테이너를 중지시켜야 한다. 또는 새로운 컨테이너를 만들 수도 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-freeze.sgml.in b/doc/ko/lxc-freeze.sgml.in
new file mode 100644 (file)
index 0000000..40bb5b8
--- /dev/null
@@ -0,0 +1,130 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-freeze</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-freeze</refname>
+
+    <refpurpose>
+      <!--
+      freeze all the container's processes
+      -->
+      컨테이너의 모든 프로세스를 동결
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-freeze</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-freeze</command> freezes all the processes running
+      inside the container. The processes will be blocked until they
+      are explicitly thawed by the <command>lxc-unfreeze</command>
+      command. This command is useful for batch managers to schedule a
+      group of processes.
+      -->
+      <command>lxc-freeze</command>는 컨테이너 내부에서 실행되는 모든 프로세스를 동결시킨다.
+      프로세스는 <command>lxc-unfreeze</command> 명령어를 이용하여 명시적으로 동결 해제시킬 때까지 블로킹 된다.
+      이 명령어는 프로세스 그룹들을 스케줄링하여 일괄처리하는 데 유용하다.
+    </para>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container was not created before with
+           the <command>lxc-create</command> command.
+            -->
+            지정한 컨테이너가  <command>lxc-create</command>로 생성된 적이 없다.
+            컨테이너가 존재하지 않는다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-info.sgml.in b/doc/ko/lxc-info.sgml.in
new file mode 100644 (file)
index 0000000..2c4cc43
--- /dev/null
@@ -0,0 +1,260 @@
+<!--
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-info</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-info</refname>
+
+    <refpurpose>
+      <!--
+      query information about a container
+      -->
+      컨테이너의 정보 조회
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-info</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-c <replaceable>KEY</replaceable></arg>
+      <arg choice="opt">-s</arg>
+      <arg choice="opt">-p</arg>
+      <arg choice="opt">-i</arg>
+      <arg choice="opt">-S</arg>
+      <arg choice="opt">-H</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-info</command> queries and shows information about a
+      container.
+      -->
+      <command>lxc-info</command>는 컨테이너에 대한 정보를 조회하고 표시한다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options --></title>
+    <variablelist>
+
+      <varlistentry>
+        <term>
+          <option>-c, --config <replaceable>KEY</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Print a configuration key from the container. This option
+            may be given multiple times to print out multiple key = value pairs.
+            -->
+            컨테이너의 설정값을 표시한다. 이 옵션은 1개 이상의 key = value 쌍을 표시할 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-s, --state</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Just print the container's state.
+            -->
+            컨테이너의 상태를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-p, --pid</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Just print the container's pid.
+            -->
+            컨테이너의 pid를 표시한다.
+            (역주 : 컨테이너 내의 init 프로세스를 의미한다)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-i, --ips</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Just print the container's IP addresses.
+            -->
+            컨테이너의 IP 주소를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-S, --stats</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Just print the container's statistics.
+            Note that for performance reasons the kernel does not account
+            kernel memory use unless a kernel memory limit is set. If a limit
+            is not set, <command>lxc-info</command> will display kernel memory
+            use as 0. A limit can be set by specifying
+            <programlisting>
+            lxc.cgroup.memory.kmem.limit_in_bytes = <replaceable>number</replaceable>
+            </programlisting>
+            in your container configuration file, see
+            <citerefentry>
+              <refentrytitle>lxc.conf</refentrytitle>
+              <manvolnum>5</manvolnum>
+            </citerefentry>.
+            -->
+            컨테이너의 통계정보를 표시한다.
+            성능상의 이유로, 커널 메모리 제한이 걸려있지 않다면 커널의 메모리 사용량은 집계되지 않는다.
+            만약 제한되어 있지 않다면, <command>lxc-info</command>는 커널 메모리 사용량을 0으로 표시한다. 메모리 제한은
+            <programlisting>
+            lxc.cgroup.memory.kmem.limit_in_bytes = <replaceable>number</replaceable>
+            </programlisting>
+            를 컨테이너 설정파일에 넣음으로써 지정할 수 있다.
+            <citerefentry>
+              <refentrytitle>lxc.conf</refentrytitle>
+              <manvolnum>5</manvolnum>
+            </citerefentry>를 참고 바란다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-H, --no-humanize</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Print the container's statistics in raw, non-humanized form. The
+            default is to print statistics in humanized form.
+            -->
+            컨테이너의 통계값을 사람이 읽기 쉬운 형태로 변환하지 않고 그대로 표시한다.
+            기본값은 사람이 읽기 쉬운 형태로 변환하는 것이다.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-info -n foo</term>
+        <listitem>
+          <para>
+            <!--
+            Show information for foo.
+            -->
+            foo 라는 이름의 컨테이너 정보를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>lxc-info -n 'ubuntu.*'</term>
+        <listitem>
+          <para>
+            <!--
+            Show information for all containers whose name starts with ubuntu.
+            -->
+            ubuntu 라는 문자열로 시작하는 이름의 컨테이너들의 정보를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>lxc-info -n foo -c lxc.network.0.veth.pair</term>
+        <listitem>
+          <para>
+            <!--
+            prints the veth pair name of foo.
+            -->
+            foo 컨테이너의 veth pair 이름을 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-ls.sgml.in b/doc/ko/lxc-ls.sgml.in
new file mode 100644 (file)
index 0000000..d7c354a
--- /dev/null
@@ -0,0 +1,293 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-ls</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-ls</refname>
+
+    <refpurpose>
+      <!--
+      list the containers existing on the system
+      -->
+      시스템 내에 존재하는 컨테이너들의 리스트 표시
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-ls</command>
+      <arg choice="opt">-1</arg>
+      <arg choice="opt">--active</arg>
+      <arg choice="opt">--frozen</arg>
+      <arg choice="opt">--running</arg>
+      <arg choice="opt">--stopped</arg>
+      <arg choice="opt">-f</arg>
+      <arg choice="opt">-F <replaceable>format</replaceable></arg>
+      <arg choice="opt">-g <replaceable>groups</replaceable></arg>
+      <arg choice="opt">--nesting=<replaceable>NUM</replaceable></arg>
+      <arg choice="opt">--filter=<replaceable>regex</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-ls</command> list the containers existing on the
+      system.
+      -->
+      <command>lxc-ls</command>는 시스템 내에 존재하는 컨테이너들의 리스트를 표시한다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+      <varlistentry>
+        <term>
+          <option>-1</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Show one entry per line. (default when /dev/stdout isn't a tty)
+            -->
+            1개의 항목를 한 줄에 표시한다. (/dev/stdout이 tty가 아닌 경우 기본)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--active</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+            List only active containers (same as &#045;&#045;frozen &#045;&#045;running).
+            -->
+            동작 중인 컨테이너들의 리스트를 표시한다. (&#045;&#045;frozen &#045;&#045;running과 동일)
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--frozen</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            List only frozen containers.
+            -->
+            동결된 컨테이너들의 리스트를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--running</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            List only running containers.
+            -->
+            실행 중인 컨테이너들의 리스트를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--stopped</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            List only stopped containers.
+            -->
+            종료되어 있는 컨테이너들의 리스트를 표시한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-f, --fancy</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Use a fancy, column-based output.
+            -->
+            예쁘게, 컬럼 기반으로 출력해준다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-F, --fancy-format <replaceable>format</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Comma separate list of column to show in the fancy output.
+            The list of accepted and default fields is listed in \-\-help.
+            -->
+            &#045;&#045;fancy로 출력할때 어떤 컬럼을 보여줄지 쉼표(,)로 구분된 리스트.
+            기본으로 표시되는 항목 및 선택할 수 있는 항목을 확인하려면 --help를 사용하면 된다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-g, --groups <replaceable>groups</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Comma separated list of groups the container must have to be displayed.
+            The parameter may be passed multiple times.
+            -->
+            표시하고자하는 컨테이너 그룹의 쉼표로 구분된 리스트.
+            이 인수는 여러번 사용될 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--nesting=<replaceable>NUM</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Show nested containers. The number of nesting levels to be shown can
+            be specified by passing a number as argument.
+            -->
+            중첩된(nested) 컨테이너들의 리스트를 표시한다. 몇번 중첩된(nested) 컨테이너를 보여줄지 숫자로 지정할 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>--filter=<replaceable>regex</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            The regular expression passed to <command>lxc-ls</command> will be
+            applied to the container name. The format is a POSIX extended
+            regular expression. It can also be given as additional argument
+            without explicitly using <option>\-\-filter</option>.
+            -->
+            <command>lxc-ls</command> 명령어 사용시 컨테이너 이름에 적용할 정규표현식이다. 형식은 POSIX 확장 정규표현식이다. 명시적으로 <option>--filter</option>을 사용하지 않고도 사용할 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-ls --fancy</term>
+        <listitem>
+        <para>
+          <!--
+          list all the containers, listing one per line along with its
+          name, state, ipv4 and ipv6 addresses.
+          -->
+          모든 컨테이너를 표시한다. 1개의 행에 컨테이너의 이름, 상태, ipv4 및 ipv6 주소가 들어있다.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-ls --active -1</term>
+       <listitem>
+       <para>
+          <!--
+         list active containers and display the list in one column.
+          -->
+          동작 중인 컨테이너들의 리스트를 1열로 표시한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  &commonoptions;
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-monitor.sgml.in b/doc/ko/lxc-monitor.sgml.in
new file mode 100644 (file)
index 0000000..ce71053
--- /dev/null
@@ -0,0 +1,238 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-monitor</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-monitor</refname>
+
+    <refpurpose>
+      <!--
+      monitor the container state
+      -->
+      컨테이너의 상태 모니터링
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-monitor</command>
+      <arg choice="opt">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-Q</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-monitor</command> monitors the state of containers. The
+      <replaceable>name</replaceable> argument may be used to specify
+      which containers to monitor. It is a regular expression, conforming
+      with posix2, so it is possible to monitor all the containers,
+      several of them or just one. If not specified,
+      <replaceable>name</replaceable> will default to '.*' which will
+      monitor all containers in <command>lxcpath</command>.
+      -->
+      <command>lxc-monitor</command>는 컨테이너의 상태를 주시한다.
+      <replaceable>name</replaceable> 인수는 어떤 컨테이너를 모니터링할지 지정한다.
+      이 인수는 POSIX 호환 정규 표현식으로 지정할 수 있다. 따라서 모든 컨테이너를 또는 그 중 몇몇만 또는 한 개의 컨테이너만 모니터링하는 것이 가능하다.
+      만약 인수가 지정되지 않았다면 <replaceable>name</replaceable>는 기본값으로 '.*'가 사용된다. 이 값은 <command>lxcpath</command>에 있는 모든 컨테이너들을 모니터링 할 수 있다.
+    </para>
+
+    <para>
+      <!--
+      The <option>-P, &#045;&#045;lxcpath</option>=PATH option may be specified multiple
+      times to monitor more than one container path. Note however that
+      containers with the same name in multiple paths will be
+      indistinguishable in the output.
+      -->
+      <option>-P, &#045;&#045;lxcpath</option>=PATH 옵션을 사용하여 컨테이너 경로를 지정할 수 있으며, 1개 이상도 가능하다.
+      하지만 각각 다른 경로에 있는 이름이 같은 컨테이너는 출력에서 구분되지 않는다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+      <varlistentry>
+       <term>
+         <option>-Q, --quit</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Ask the lxc-monitord daemon on each given <command>lxcpath</command>
+           to quit. After receiving this command, lxc-monitord will exit
+           immediately as soon as it has no clients instead of waiting the
+           normal 30 seconds for new clients. This is useful if you need to
+           unmount the filesystem <command>lxcpath</command> is on.
+            -->
+            지정한 <command>lxcpath</command> 각각에 대한 lxc-monitord 데몬을 종료하도록 요청한다.
+            lxc-monitord는 일반적으로 클라이언트가 없으면, 새로운 클라이언트를 를 30초 동안 기다린 후 종료된다. 하지만 이 명령어를 실행한 후에는 클라이언트가 없으면 바로 종료된다.
+            이 옵션은 <command>lxcpath</command>의 파일시스템을 바로 unmount할 필요가 있을때, 유용하다.
+         </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+       <term>lxc-monitor -n foo</term>
+       <listitem>
+       <para>
+          <!--
+         will monitor the different states for container foo.
+          -->
+          foo 컨테이너의 상태 변화를 모니터링한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-monitor -n 'foo|bar'</term>
+       <listitem>
+       <para>
+          <!--
+         will monitor the different states for container foo and bar.
+          -->
+          컨테이너 foo와 bar의 상태 변화를 모니터링 한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-monitor -n '[f|b].*'</term>
+       <listitem>
+       <para>
+          <!--
+         will monitor the different states for container with the
+         name beginning with letter 'f' or 'b'.
+          -->
+          이름이 'f' 또는 'b'로 시작하는 컨테이너의 상태 변화를 모니터링한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-monitor -n '.*'</term>
+       <listitem>
+       <para>
+          <!--
+         will monitor the different states for all containers.
+          -->
+          모든 컨테이너들의 상태 변화를 모니터링한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container was not created before with
+           the <command>lxc-create</command> command.
+            -->
+            지정한 컨테이너가  <command>lxc-create</command>로 생성된 적이 없다.
+            컨테이너가 존재하지 않는다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+
+    <simpara>
+      <citerefentry>
+       <refentrytitle>regex</refentrytitle>
+       <manvolnum>7</manvolnum>
+      </citerefentry>,
+    </simpara>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-snapshot.sgml.in b/doc/ko/lxc-snapshot.sgml.in
new file mode 100644 (file)
index 0000000..5f05e31
--- /dev/null
@@ -0,0 +1,208 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Inc. 2007, 2008
+
+Authors:
+Serge Hallyn <serge.hallyn at ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-snapshot</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-snapshot</refname>
+
+    <refpurpose>
+      <!--
+      Snapshot an existing container.
+      -->
+      존재하는 컨테이너의 스냅샷 생성 및 복원
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-snapshot</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-c, --comment <replaceable>file</replaceable></arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-snapshot</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="req">-d, -destroy <replaceable>snapshot-name</replaceable></arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-snapshot</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="req">-L, --list </arg>
+      <arg choice="opt">-C, --showcomments </arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-snapshot</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="req">-r, -restore <replaceable>snapshot-name</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable>newname</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-snapshot</command> creates, lists, and restores
+      container snapshots.
+      -->
+      <command>lxc-snapshot</command>는 컨테이너의 스냅샷을 생성, 복원 그리고 리스트를 표시한다.
+      (역주 : 컨테이너 파일시스템을 대상으로 한다는 점에서 <command>lxc-checkpoint</command>와는 다르다)
+    </para>
+    <para>
+      <!--
+      Snapshots are stored as snapshotted containers under the container's configuration path. For instance, if the container's configuration path is <filename>/var/lib/lxc</filename> and the container is <filename>c1</filename>, then the first snapshot will be stored as container <filename>snap0</filename> under the path <filename>/var/lib/lxc/c1/snaps</filename>.
+      If <filename>/var/lib/lxcsnaps</filename>, as used by LXC 1.0, already exists, then it will continue to be used.
+        -->
+      스냅샷은 컨테이너 설정 경로 밑에 스냅샷된 컨테이너처럼 저장된다.
+      예를 들어, 만약 컨테이너 설정 경로가 <filename>/var/lib/lxc</filename>이고 컨테이너 이름이 <filename>c1</filename>라면, 첫번째 스냅샷은 <filename>/var/lib/lxc/c1/snaps</filename> 밑에 <filename>snap0</filename>라는 이름의 컨테이너로 저장 된다.
+      LXC 1.0 때 사용됬던 <filename>/var/lib/lxcsnaps</filename>가 존재하는 경우라면, 해당 경로가 계속 쓰이게 된다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+         <varlistentry>
+           <term> <option>-c,--comment <replaceable>comment_file</replaceable></option> </term>
+          <listitem>
+           <para>
+              <!--
+              Associate the comment in <replaceable>comment_file</replaceable> with the newly created snapshot.
+              -->
+              새로 생성되는 스냅샷에 <replaceable>comment_file</replaceable>에 있는 주석을 단다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-d,--destroy snapshot-name</option> </term>
+          <listitem>
+             <!--
+           <para> Destroy the named snapshot.  If the named snapshot is ALL, then all snapshots
+           will be destroyed.</para>
+            -->
+            지정한 스냅샷을 제거한다. 스냅샷의 이름이 ALL인 경우, 모든 스냅샷을 제거한다.
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-L,--list </option> </term>
+          <listitem>
+           <para>
+              <!--
+              List existing snapshots.
+              -->
+              존재하는 스냅샷의 리스트를 표시한다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-C,--showcomments </option> </term>
+          <listitem>
+           <para>
+              <!--
+              Show snapshot comments in the snapshots listings.
+              -->
+              스냅샷의 리스트를 표시할때 스냅샷의 주석도 함께 표시한다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-r,--restore snapshot-name</option> </term>
+          <listitem>
+           <para>
+              <!--
+              Restore the named snapshot, meaning a full new container is created which is a copy of the snapshot.
+              -->
+              지정한 스냅샷을 복원한다, 즉, 스냅샷을 복사하여 완전히 새로운 컨테이너가 생성된다는 것을 의미한다.
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-N, --newname</option> </term>
+          <listitem>
+            <para>
+             <!--
+              When restoring a snapshot, the last optional argument if not given explicitly Via <command>\-\-newname</command> is the name to use for the restored container.  If the newname is identical to the original name of the container, then the original container will be destroyed and the restored container will take its place. Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots.
+              -->
+              스냅샷을 복원할 때, 복원된 컨테이너의 이름을 <command>--newname</command>로 명시적으로 지정하지 않았다면 마지막 인자를 이름으로 사용한다. 만약 newname이 원래 컨테이너의 이름과 같다면, 원래 컨테이너는 제거되고 복원되는 컨테이너로 교체된다. aufs, overlayfs, zfs의 경우에는 원본 스냅샷의 제거가 불가능하다는 것에 주의해야 한다.
+           </para>
+          </listitem>
+         </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Serge Hallyn <email>serge.hallyn@ubuntu.com </email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-start-ephemeral.sgml.in b/doc/ko/lxc-start-ephemeral.sgml.in
new file mode 100644 (file)
index 0000000..48947f6
--- /dev/null
@@ -0,0 +1,318 @@
+
+<!--
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-start-ephemeral</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-start-ephemeral</refname>
+
+    <refpurpose>
+      <!--
+      start an ephemeral copy of an existing container
+      -->
+      존재하는 컨테이너를 임시 복사본으로 시작
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-start-ephemeral</command>
+      <arg choice="opt">-o</arg>
+      <arg choice="opt">-n</arg>
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">--bdir</arg>
+      <arg choice="opt">--user</arg>
+      <arg choice="opt">--key</arg>
+      <arg choice="opt">--storage-type</arg>
+      <arg choice="opt">--union-type</arg>
+      <arg choice="opt">--keep-data</arg>
+      <arg choice="opt">COMMAND</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-start-ephemeral</command> start an ephemeral copy of an
+      existing container.
+      -->
+      <command>lxc-start-ephemeral</command>는 존재하는 컨테이너를 임시 복사본으로 시작시킨다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+      <varlistentry>
+        <term>
+          <option>-o, --orig <replaceable>orig</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Original container name
+            -->
+            원본 컨테이너 이름
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-n, --name <replaceable>name</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Name of the ephemeral container (defaults to a random suffix).
+            -->
+            임시 컨테이너의 이름 (기본값은 무작위한 접미사를 붙이는 것)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-d, --daemon</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Start the container in background and print the name and IP.
+            This option can't be used if a command is passed.
+            -->
+            컨테이너를 백그라운드로 시작한다. 그리고 이름과 IP를 표시한다.
+            옵션으로 명령어를 넘길 경우, 이 옵션은 사용하지 못한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-b, --bdir <replaceable>bdir</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Directory to bind mount into container.
+            Can be passed multiple times.
+            -->
+            컨테이너로 바인드 마운트할 디렉토리.
+            여러번 인자로 넘겨줄 수 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-u, --user <replaceable>user</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            The user to connect to the container as.
+            Used when passing a command to lxc-start-ephemeral.
+            -->
+            컨테이너에 연결할 사용자.
+            lxc-start-ephemeral로 명령어를 넘길때 사용한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-S, --key <replaceable>key</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Copy the provided SSH public key into the container.
+            -->
+            컨테이너 안으로 지정한 SSH 공개키를 복사한다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-s, --storage-type <replaceable>storage type</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Specify the type of storage used by the container. Valid types are tmpfs or dir.
+              -->
+            컨테이너가 사용하는 저장소 형태를 지정한다. 가능한 형태는 tmpfs, dir이다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-U, --union-type <replaceable>union type</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Force a specific union file system.
+            Can be one of: overlayfs aufs
+            -->
+            지정한 union 파일시스템을 사용한다.
+            가능한 파일시스템은  overlayfs, aufs이다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>-k, --keep-data</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Use a persistent backend instead of tmpfs.
+            With this option, you can lxc-stop and lxc-start the no longer so
+            ephemeral container (it's still an overlay, but a persistent one).
+            -->
+            tmpfs 대신 영구적인 백엔드를 사용한다.
+            이 옵션을 사용하면, 더이상 임시 컨테이너가 아니기 때문에 lxc-stop이나 lxc-start를 사용할 수 있게 된다. (여전히 오버레이 상태이지만 영구적이다)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <option>COMMAND</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Immediately run the provided command in the container.
+            This uses attach if the kernel supports it, otherwise uses ssh.
+            This is incompatible with daemon mode.
+            -->
+            지정한 명령어를 컨테이너 안에서 바로 실행한다.
+            커널이 attach를 지원하면 attach를 사용하고, 지원하지 않으면 ssh를 사용한다.
+            이 옵션은 데몬 모드와 같이 사용할 수 없다.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+
+    <simpara>
+      <citerefentry>
+        <refentrytitle>lxc-start</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry>,
+    </simpara>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-start-ephemeral -o p1</term>
+        <listitem>
+        <para>
+          <!--
+          Simply start an ephemeral container and attach to the console.
+          This container will be based on existing container "p1".
+          -->
+          단순히 임시 복사본 컨테이너를 시작하고, console에 연결한다.
+          임시 컨테이너는 컨테이너 p1을 기반으로 한다.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>lxc-start-ephemeral -o p1 -n p1-ephemeral -d</term>
+        <listitem>
+        <para>
+          <!--
+          Start an ephemeral container based on p1 called p1-ephemeral and
+          print its IP and name to the console instead of attaching.
+          -->
+          컨테이너 p1을 기반으로 임시 컨테이너 p1-ephemeral을 시작한다.
+          console에 연결하지 않고, 컨테이너의 IP와 이름을 출력한다.
+        </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Notes -->주의</title>
+    <para>
+      <!--
+      <command>lxc-start-ephemeral</command> is deprecated in favor of
+      <command>lxc-copy</command>.
+      -->
+      <command>lxc-start-ephemeral</command>는 <command>lxc-copy</command>로 대체되었으며, 제거될 예정이다.
+    </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-start.sgml.in b/doc/ko/lxc-start.sgml.in
new file mode 100644 (file)
index 0000000..a507747
--- /dev/null
@@ -0,0 +1,360 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-start</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-start</refname>
+
+    <refpurpose>
+      <!--
+      run an application inside a container.
+      -->
+      컨테이너 시작(실행)
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-start</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
+      <arg choice="opt">-c <replaceable>console_device</replaceable></arg>
+      <arg choice="opt">-L <replaceable>console_logfile</replaceable></arg>
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">-F</arg>
+      <arg choice="opt">-p <replaceable>pid_file</replaceable></arg>
+      <arg choice="opt">-s KEY=VAL</arg>
+      <arg choice="opt">-C</arg>
+      <arg choice="opt">--share-[net|ipc|uts] <replaceable>name|pid</replaceable></arg>
+      <arg choice="opt">command</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-start</command> runs the specified
+      <replaceable>command</replaceable> inside the container
+      specified by <replaceable>name</replaceable>.
+      -->
+      <command>lxc-start</command>는 지정된 <replaceable>command</replaceable>를 <replaceable>name</replaceable>이라는 이름의 컨테이너 내에서 실행한다.
+      (역주 : 컨테이너를 시작한다)
+    </para>
+    <para>
+      <!--
+      It will setup the container
+      according to the configuration previously defined with the
+      lxc-create command or with the configuration file parameter.
+      If no configuration is
+      defined, the default isolation is used.
+      -->
+      이 명령어는 <command>lxc-create</command> 정의했던 설정을 토대로 또는 인수를 통해 넘긴 설정파일을 토대로 컨테이너를 세팅한다.
+      만약 정의된 설정이 없다면, 기본 고립 환경을 사용한다.
+    </para>
+    <para>
+      <!--
+      If no command is specified, <command>lxc-start</command> will
+      use the command defined in lxc.init_cmd or if not set, the default
+      <command>"/sbin/init"</command> command to run a system
+      container.
+      -->
+      만약 명령어가 지정되지 않았다면, <command>lxc-start</command>는 lxc.init_cmd에 정의된 명령어를 사용한다. 만약 그마저도 없다면 <command>"/sbin/init"</command>명령어를 사용한다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-d, --daemon</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Run the container as a daemon. As the container has no
+           more tty, if an error occurs nothing will be displayed,
+           the log file can be used to check the error.
+            -->
+            컨테이너를 데몬으로 실행한다.
+            에러가 발생하더라도 컨테이너가 tty를 가지지 않기 때문에 에러는 표시되지 않는다.
+            대신 로그 파일을 에러를 확인하는데 사용할 수 있다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-F, --foreground</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Run the container in the foreground. In this mode, the container
+           console will be attached to the current tty and signals will be routed
+           directly to the container.
+            -->
+            컨테이너를 포그라운드로 실행한다. 이 모드에서는 컨테이너의 콘솔은 현재 tty에 붙는다. 그리고 시그널들은 컨테이너로 직접 보내지게 된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-p, --pidfile <replaceable>pid_file</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Create a file with the process id.
+            -->
+            프로세스 ID를 넣은 파일을 생성한다.
+            (역주 : systemd의 PIDFile= 옵션 등에 유용하게 사용가능하다)
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-f, --rcfile <replaceable>config_file</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the configuration file to configure the virtualization
+           and isolation functionalities for the container.
+            -->
+            컨테이너의 가상화나 고립 기능을 설정할 때 쓰일 설정파일을 지정한다.
+         </para>
+         <para>
+            <!--
+          This configuration file if present will be used even if there is
+          already a configuration file present in the previously created
+          container (via lxc-create).
+           -->
+           지정한 설정파일이 존재한다면, 이전에 생성된(lxc-create를 통해) 컨테
+이너에 설정파일이 이미 존재한다고 하더라도 지정한 설정파일을 사용한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-c,
+         --console <replaceable>console_device</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify a device to use for the container's console, for example
+            /dev/tty8. If this option is not specified the current terminal
+            will be used unless <option>-d</option> is specified.
+            -->
+            컨테이너의 콘솔로 사용할 디바이스를 지정한다. 예를 들어 /dev/tty8과 같이 지정가능하다. 만약 이 옵션이 지정되지 않았고 <option>-d</option>가 지정되이 않았다면, 현재 터미널이 사용된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-L,
+         --console-log <replaceable>console_logfile</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify a file to log the container's console output to.
+            -->
+            컨테이너의 콘솔 출력을 기록할 파일을 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-s, --define <replaceable>KEY=VAL</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Assign value <replaceable>VAL</replaceable> to configuration
+           variable <replaceable>KEY</replaceable>. This overrides any
+           assignment done in <replaceable>config_file</replaceable>.
+            -->
+            지정한 설정 변수 <replaceable>KEY</replaceable>에 <replaceable>VAL</replaceable>값을 지정한다.
+            이 것은 이전에 <replaceable>config_file</replaceable>에서 지정했던 값들을 덮어쓴다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-C,
+         --close-all-fds</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         If any file descriptors are inherited, close them.  If this option
+         is not specified, then <command>lxc-start</command> will exit with
+         failure instead. Note: <replaceable>&#045;&#045;daemon</replaceable> implies
+         <replaceable>&#045;&#045;close-all-fds</replaceable>.
+          -->
+            상속 받는 파일 디스크립터가 있다면, 전부 닫는다. 만약 이 옵션이 지정되지 않았을 경우 <command>lxc-start</command>는 실패와 함께 종료된다. 주의 : <replaceable>&#045;&#045;daemon</replaceable>는 <replaceable>&#045;&#045;close-all-fds</replaceable>를 포함하고 있다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--share-net <replaceable>name|pid</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+            Inherit a network namespace from
+           a <replaceable>name</replaceable> container or
+           a <replaceable>pid</replaceable>. The network namespace
+           will continue to be managed by the original owner. The
+           network configuration of the starting container is ignored
+           and the up/down scripts won't be executed.
+            -->
+            <replaceable>name</replaceable> 컨테이너 또는 <replaceable>pid</replaceable>로부터 네트워크 네임스페이스를 상속받는다. 네트워크 네임스페이스는 원래 소유자가 계속 관리하게 된다. 시작하는 컨테이너의 네트워크 설정은 무시되고 up/down 스크립트는 실행되지 않는다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--share-ipc <replaceable>name|pid</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+            Inherit an IPC namespace from
+           a <replaceable>name</replaceable> container or
+           a <replaceable>pid</replaceable>.
+            -->
+            <replaceable>name</replaceable> 컨테이너 또는 <replaceable>pid</replaceable>로부터 IPC 네임스페이스를 상속받는다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>--share-uts <replaceable>name|pid</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+            Inherit a UTS namespace from
+           a <replaceable>name</replaceable> container or
+           a <replaceable>pid</replaceable>. The starting LXC will
+           not set the hostname, but the container OS may do it
+           anyway.
+            -->
+            <replaceable>name</replaceable> 컨테이너 또는 <replaceable>pid</replaceable>로부터 UTS 네임스페이스를 상속받는다. LXC는 시작할 때 호스트이름을 설정하지 않는다. 다만, 컨테이너 OS가 설정할 수 있다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container is busy</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container is already running an
+           application. You should stop it before reuse this
+           container or create a new one.
+            -->
+            지정한 컨테이너가 이미 실행중인 경우이다. 컨테이너를 사용하고 싶다면
+            컨테이너를 중지시켜야 한다. 또는 새로운 컨테이너를 만들 수도 있다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-stop.sgml.in b/doc/ko/lxc-stop.sgml.in
new file mode 100644 (file)
index 0000000..e50f029
--- /dev/null
@@ -0,0 +1,292 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-stop</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-stop</refname>
+
+    <refpurpose>
+      <!--
+      stop the application running inside a container
+      -->
+      컨테이너 종료
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-stop</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-W</arg>
+      <arg choice="opt">-r</arg>
+      <arg choice="opt">-t <replaceable>timeout</replaceable></arg>
+      <arg choice="opt">-k</arg>
+      <arg choice="opt">--nokill</arg>
+      <arg choice="opt">--nolock</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-stop</command> reboots, cleanly shuts down, or kills
+      all the processes inside the container.  By default, it will
+      request a clean shutdown of the container by sending
+      <command>lxc.haltsignal</command> (defaults to SIGPWR) to
+      the container's init process, waiting up to 60 seconds for the container
+      to exit, and then returning. If the container fails to cleanly exit in
+      60 seconds, it will be sent the <command>lxc.stopsignal</command>
+      (defaults to SIGKILL) to force it to shut down. A request to reboot will
+      send the <command>lxc.rebootsignal</command> (defaults to SIGINT) to the
+      container's init process.
+      -->
+      <command>lxc-stop</command> 는 재뷰탕, 종료, 또는 컨테이너 내의 모든 프로세스를 강제종료 시킨다. 기본 동작은 컨테이너에게 <command>lxc.haltsignal</command> 시그널(기본값은 SIGPWR)을 컨테이너 init 프로세스에게 날려, 컨테이너가 종료되게 요청하는 것이다. 60초 동안 컨테이너가 종료되는 것을 기다리고 리턴된다.
+만약 컨테이너가 60초안에 종료되지 않는다면 <command>lxc.stopsignal</command> 시그널(기본값은 SIGKILL)을 날려 강제로 종료시킨다. 재부팅 요청시에는 <command>lxc.rebootsignal</command> 시그널(기본값은 SIGINT)를 컨테이너 init 프로세스에게 날린다.
+    </para>
+
+    <para>
+      <!--
+      The <optional>-W</optional>, <optional>-r</optional>,
+      <optional>-k</optional> and <optional>\-\-nokill</optional>
+      options specify the action to perform.
+      <optional>-W</optional> indicates that after performing the specified
+      action, <command>lxc-stop</command> should immediately exit, while
+      <optional>-t TIMEOUT</optional> specifies the maximum amount of time
+      to wait for the container to complete the shutdown or reboot.
+      -->
+      <optional>-W</optional>, <optional>-r</optional>, <optional>-s</optional>, <optional>-k</optional>, <optional>--nokill</optional> 옵션은 어떤 동작을 수행할지 지정한다.
+      <optional>-W</optional>는 <command>lxc-stop</command>가 동작 수행후 즉각적으로 종료되게 지정한다. <optional>-t TIMEOUT</optional>는 동작이 완료되기까지 기다릴 최대 시간을 지정한다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+    <varlistentry>
+       <term>
+         <option>-r,--reboot </option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Request a reboot of the container.
+            -->
+            컨테이너 재부팅을 요청한다.
+         </para>
+       </listitem>
+       </varlistentry>
+
+    <varlistentry>
+       <term>
+         <option>-k,--kill </option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+        Rather than requesting a clean shutdown of the container, explicitly
+        kill all tasks in the container.  This is the legacy
+        <command>lxc-stop</command> behavior.
+        -->
+           컨테이너가 깨끗이 종료되는 것 대신 명시적으로 컨테이너 내의 모든 작업들을 강제종료 시킨다. 이것은 이전 <command>lxc-stop</command>의 동작이다.
+         </para>
+       </listitem>
+    </varlistentry>
+
+    <varlistentry>
+       <term>
+         <option>--nokill</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Only request a clean shutdown, do not kill the container tasks if the
+               clean shutdown fails.
+              -->
+            깨끗이 종료되도록 요청한다. 만약 종료가 실패하더라도 컨테이너 작업을 강제로 종료시키지 않는다.
+         </para>
+       </listitem>
+       </varlistentry>
+
+    <varlistentry>
+       <term>
+         <option>--nolock </option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+       This option avoids the use of any of the API lxc locking, and should
+       only be used if <command>lxc-stop</command> is hanging due to a bad
+       system state.
+              -->
+            이 옵션은 lxc API에서 락킹을 사용하지 않는다.  <command>lxc-stop</command>이 잘못된 시스템 상태로 인해, 응답이 없게 되었을 경우에만 사용된다.
+         </para>
+       </listitem>
+    </varlistentry>
+
+    <varlistentry>
+       <term>
+         <option>-W,--nowait </option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Simply perform the requestion action (reboot, shutdown, or hard
+               kill) and exit.
+              -->
+            동작 수행(재부팅, 종료, 강제종료)을 요청하고 바로 죵료한다.
+         </para>
+       </listitem>
+       </varlistentry>
+
+    <varlistentry>
+       <term>
+         <option>-t,--timeout <replaceable>TIMEOUT</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Wait TIMEOUT seconds before hard-stopping the container.
+              -->
+            컨테이너를 강제종료 하기 전에 TIMEOUT 초 만큼 기다린다.
+         </para>
+       </listitem>
+       </varlistentry>
+
+  </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Exit value -->종료</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>0</term>
+        <listitem>
+          <para>
+            <!--
+           The container was successfully stopped.
+            -->
+            컨테이너가 성공적으로 종료됬다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>1</term>
+        <listitem>
+          <para>
+            <!--
+           An error occurred while stopping the container.
+            -->
+            컨테이너를 종료하던 도중 오류가 발생하였다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>2</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container exists but was not running.
+            -->
+            지정한 컨테이너가 있지만 실행되 있지는 않다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container was not created before with
+           the <command>lxc-create</command> command.
+            -->
+            지정한 컨테이너가  <command>lxc-create</command>로 생성된 적이 없다.
+            컨테이너가 존재하지 않는다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-top.sgml.in b/doc/ko/lxc-top.sgml.in
new file mode 100644 (file)
index 0000000..3c34b6b
--- /dev/null
@@ -0,0 +1,205 @@
+<!--
+
+Copyright © 2012 Oracle.
+
+Authors:
+Dwight Engen <dwight.engen@oracle.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-top</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-top</refname>
+
+    <refpurpose>
+      <!--
+      monitor container statistics
+      -->
+      컨테이너의 통계정보 표시
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-top</command>
+      <arg choice="opt">--help</arg>
+      <arg choice="opt">--delay <replaceable>delay</replaceable></arg>
+      <arg choice="opt">--sort <replaceable>sortby</replaceable></arg>
+      <arg choice="opt">--reverse</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-top</command> displays container statistics. The output
+      is updated every <replaceable>delay</replaceable> seconds, and is
+      ordered according to the <replaceable>sortby</replaceable> value
+      given. <command>lxc-top</command> will display as many containers as
+      can fit in your terminal. Press 'q' to quit. Press one of the sort
+      key letters to sort by that statistic. Pressing a sort key letter a
+      second time reverses the sort order.
+      -->
+      <command>lxc-top</command>는 컨테이너의 통계정보를 표시한다. 출력은 매 <replaceable>delay</replaceable>초마다 갱신된다.
+      그리고 <replaceable>sortby</replaceable>로 지정한 항목에 대하여 정렬을 수행한다. <command>lxc-top</command>명령어는 현재 터미널의 크기에 맞게 가능한 많은 컨테이너를 표시한다. 'q'를 누르면 나갈 수 있다. 정렬 항목의 문자를 입력하면 그 항목에 대해 정렬한다. 해당 문자를 두번 입력하면 정렬 순서가 바뀐다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+        <term>
+          <option>-d, --delay <replaceable>delay</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Amount of time in seconds to delay between screen updates.
+            The default is 3 seconds.
+            -->
+            화면을 갱신하는 시간을 초단위로 지정한다.
+            기본값은 3초이다.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <option>-s, --sort <replaceable>sortby</replaceable></option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Sort the containers by name, cpu use, or memory use. The
+            <replaceable>sortby</replaceable> argument should be one of
+            the letters n,c,b,m,k to sort by name, cpu use, block I/O, memory,
+            or kernel memory use respectively. The default is 'n'.
+            -->
+            이름, CPU 사용량, 메모리 사용량에 대해 정렬한다. <replaceable>sortby</replaceable> 인수에는 최소한 한개의 n, c, b, m, k 문자가 있어야 하며, 각각 CPU 사용량, 블록 I/O, 메모리 사용량, 커널 메모리 사용량을 가리킨다. 기본값은 'n'이다.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <option>-r, --reverse</option>
+        </term>
+        <listitem>
+          <para>
+            <!--
+            Reverse the default sort order. By default, names sort in
+            ascending alphabetical order and values sort in descending
+            amounts (ie. largest value first).
+            -->
+            정렬 순서를 바꾼다. 기본 동작은, 이름은 오름차순 알파벳 정렬이고 값은 내림차순 정렬(큰 값이 먼저)이다.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Example -->예제</title>
+    <variablelist>
+      <varlistentry>
+        <term>lxc-top --delay 1 --sort m</term>
+        <listitem>
+        <para>
+          <!--
+          Display containers, updating every second, sorted by memory use.
+          -->
+          컨테이너를 1초마다 갱신하면서, 메모리 사용량으로 정렬해서 표시한다.
+        </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Notes -->주의</title>
+    <para>
+      <!--
+      For performance reasons the kernel does not account kernel memory use
+      unless a kernel memory limit is set. If a limit is not set, <command>
+      lxc-top</command> will display kernel memory use as 0. If no containers
+      are being accounted, the KMem column will not be displayed. A limit can
+      be set by specifying
+      <programlisting>
+      lxc.cgroup.memory.kmem.limit_in_bytes = <replaceable>number</replaceable>
+      </programlisting>
+      in your container configuration file, see
+      <citerefentry>
+        <refentrytitle>lxc.conf</refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>.
+      -->
+      성능상의 이유로, 커널 메모리 제한이 걸려있지 않다면 커널 메모리 사용량을 집계하지 않는다.
+      메모리 제한이 걸려있지 않다면, <command>lxc-top</command>는 커널 메모리 사용량을 0으로 표시한다. 만약 집계되는 컨테이너가 하나도 없다면, KMem 열은 표시되지 않는다. 메모리 제한은
+      <programlisting>
+      lxc.cgroup.memory.kmem.limit_in_bytes = <replaceable>number</replaceable>
+      </programlisting>
+      으로 컨테이너 설정파일에서 지정할 수 있다.
+      <citerefentry>
+        <refentrytitle>lxc.conf</refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>
+      를 참고하면 된다.
+    </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Dwight Engen <email>dwight.engen@oracle.com</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
similarity index 52%
rename from doc/legacy/lxc-ls.sgml.in
rename to doc/ko/lxc-unfreeze.sgml.in
index bed9b8a..f78d9ab 100644 (file)
@@ -1,4 +1,3 @@
-
 <!--
 
 lxc: linux Container library
@@ -6,7 +5,7 @@ lxc: linux Container library
 (C) Copyright IBM Corp. 2007, 2008
 
 Authors:
-Daniel Lezcano <dlezcano at fr.ibm.com>
+Daniel Lezcano <daniel.lezcano at free.fr>
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
@@ -22,11 +21,15 @@ You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
 -->
 
 <!DOCTYPE refentry PUBLIC @docdtd@ [
 
-<!ENTITY seealso SYSTEM "@builddir@/../see_also.sgml">
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
 ]>
 
 <refentry>
@@ -34,105 +37,71 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
 
   <refmeta>
-    <refentrytitle>lxc-ls</refentrytitle>
+    <refentrytitle>lxc-unfreeze</refentrytitle>
     <manvolnum>1</manvolnum>
   </refmeta>
 
   <refnamediv>
-    <refname>lxc-ls</refname>
+    <refname>lxc-unfreeze</refname>
 
     <refpurpose>
-      list the containers existing on the system
+      <!--
+      thaw all the container's processes
+      -->
+      컨테이너의 모든 프로세스를 동결해제
     </refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
     <cmdsynopsis>
-      <command>lxc-ls</command>
-      <arg choice="opt">--active</arg>
-      <arg choice="opt"><replaceable>ls options</replaceable></arg>
+      <command>lxc-unfreeze</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
-    <title>Description</title>
+    <title><!-- Description -->설명</title>
+
     <para>
-      <command>lxc-ls</command> list the containers existing on the
-      system.
+      <!--
+      <command>lxc-unfreeze</command> will thaw all the processes
+      previously frozen by the <command>lxc-freeze</command> command.
+      -->
+      <command>lxc-unfreeze</command>는 이전에 <command>lxc-freeze</command>로 동결 시켰던 모든 프로세스들을 동결해제한다.
     </para>
-  </refsect1>
-
-  <refsect1>
-    <title>Options</title>
-    <variablelist>
-
-      <varlistentry>
-       <term>
-         <option><optional>--active</optional></option>
-       </term>
-       <listitem>
-         <para>
-           List active containers.
-         </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>
-         <option><optional><replaceable>ls options</replaceable></optional></option>
-       </term>
-       <listitem>
-         <para>
-           The option passed to <command>lxc-ls</command> are the
-           same as the <command>ls</command> command.
-         </para>
-       </listitem>
-      </varlistentry>
-
-    </variablelist>
 
   </refsect1>
 
+  &commonoptions;
+
   <refsect1>
-    <title>Examples</title>
+    <title><!-- Diagnostic -->진단</title>
+
     <variablelist>
-      <varlistentry>
-       <term>lxc-ls -l</term>
-       <listitem>
-       <para>
-         list all the container and their permissions.
-       </para>
-       </listitem>
-      </varlistentry>
 
       <varlistentry>
-       <term>lxc-ls --active -1</term>
-       <listitem>
-       <para>
-         list active containers and display the list in one column.
-       </para>
-       </listitem>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container was not created before with
+           the <command>lxc-create</command> command.
+            -->
+            지정한 컨테이너가  <command>lxc-create</command>로 생성된 적이 없다.
+            컨테이너가 존재하지 않는다.
+          </para>
+        </listitem>
       </varlistentry>
 
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
 
-    <simpara>
-      <citerefentry>
-       <refentrytitle>ls</refentrytitle>
-       <manvolnum>1</manvolnum>
-      </citerefentry>,
-    </simpara>
+    </variablelist>
 
   </refsect1>
 
   &seealso;
 
   <refsect1>
-    <title>Author</title>
+    <title><!-- Author -->저자</title>
     <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
   </refsect1>
 
diff --git a/doc/ko/lxc-unshare.sgml.in b/doc/ko/lxc-unshare.sgml.in
new file mode 100644 (file)
index 0000000..6e4d07e
--- /dev/null
@@ -0,0 +1,288 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+Serge Hallyn <serge.hallyn at ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-unshare</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-unshare</refname>
+
+    <refpurpose>
+      <!--
+      Run a task in a new set of namespaces.
+      -->
+      새로운 네임스페이스 내에서 태스크 실행
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-unshare</command>
+      <arg choice="req">-s <replaceable>namespaces</replaceable></arg>
+      <arg choice="opt">-u <replaceable>user</replaceable></arg>
+      <arg choice="opt">-H <replaceable>hostname</replaceable></arg>
+      <arg choice="opt">-i <replaceable>ifname</replaceable></arg>
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">-M</arg>
+      <arg choice="req">command</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-unshare</command> can be used to run a task in a cloned set
+      of namespaces.  This command is mainly provided for testing purposes.
+      Despite its name, it always uses clone rather than unshare to create
+      the new task with fresh namespaces.  Apart from testing kernel
+      regressions this should make no difference.
+      -->
+      <command>lxc-unshare</command>는 복제된 네임스페이스 내에서 태스크를 실행한다.
+      이 명령어는 주로 테스트 목적으로 사용된다.
+      이러한 이름에도 불구하고, 새 네임스페이스에 새로운 태스크를 생성하기 위해 unshare 대신 clone을 사용한다.
+      테스트 중인 커널 버전이 낮아지지 않는다면, 별 차이는 없다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-s <replaceable>namespaces</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the namespaces to attach to, as a pipe-separated list,
+           e.g. <replaceable>NETWORK|IPC</replaceable>. Allowed values are
+           <replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>,
+           <replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>,
+           <replaceable>USER </replaceable> and
+           <replaceable>NETWORK</replaceable>. This allows one to change
+           the context of the process to e.g. the network namespace of the
+           container while retaining the other namespaces as those of the
+            host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
+            -->
+            붙일 네임스페이스를 지정한다.
+            <replaceable>NETWORK|IPC</replaceable>와 같이 파이프(|)로 구분된 리스트를 사용할 수 있다. 허용되는 값은 <replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>, <replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>, <replaceable>USER </replaceable>, <replaceable>NETWORK</replaceable>이다. 이를 사용하여, 컨테이너의 네트워크 네임스페이스를 사용하면서도 다른 네임스페이스는 호스트의 것을 그대로 사용하는 등의 조작이 가능하다.
+            (파이프 기호는 <replaceable>MOUNT\|PID</replaceable>처럼 \로 처리를 해주거나, <replaceable>"MOUNT|PID"</replaceable>처럼 따옴표를 붙여야 한다.)
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-u <replaceable>user</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify a user which the new task should become.
+            -->
+            새로운 태스크를 실행할 사용자를 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-H <replaceable>hostname</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Set the hostname in the new container.  Only allowed if
+           the UTSNAME namespace is set.
+            -->
+            새로운 컨테이너의 호스트이름을 지정한다. UTS 네임스페이스가 설정되었을 때만 가능하다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-i <replaceable>interfacename</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Move the named interface into the container.  Only allowed
+           if the NETWORK namespace is set.  You may specify this
+           argument multiple times to move multiple interfaces into
+           container.
+            -->
+            지정한 이름의 네트워크 인터페이스를 컨테이너 내부로 옮긴다. NETWORK 네임스페이스가 설정되었을 때만 가능하다. 여러개의 인터페이스를 옮기기 위해 여러번 이 인수를 지정하는 것도 가능하다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-d</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Daemonize (do not wait for the container to exit before exiting)
+            -->
+            데몬화 한다. (컨테이너가 종료되기 전까지 기다리지 않는다)
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-M</option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Mount default filesystems (/proc /dev/shm and /dev/mqueue)
+           in the container.  Only allowed if MOUNT namespace is set.
+            -->
+            컨테이너 내부에 (/proc /dev/shm and /dev/mqueue)같은 기본 파일 시스템들을 마운트 한다. MOUNT 네임스페이스가 설정되었을 때만 가능하다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+      <para>
+        <!--
+        To spawn a new shell with its own UTS (hostname) namespace,
+        <programlisting>
+          lxc-unshare -s UTSNAME /bin/bash
+        </programlisting>
+       If the hostname is changed in that shell, the change will not be
+       reflected on the host.
+        -->
+        자신만의 UTS(hostname) 네임스페이스를 갖는 새로운 쉘을 실행하려면 아래처럼 하면 된다.
+        <programlisting>
+          lxc-unshare -s UTSNAME /bin/bash
+        </programlisting>
+        만약, 그 쉘에서 호스트이름이 변경되어도 호스트에는 영향을 끼치지 않는다.
+      </para>
+      <para>
+        <!--
+        To spawn a shell in a new network, pid, and mount namespace,
+        <programlisting>
+          lxc-unshare -s "NETWORK|PID|MOUNT" /bin/bash
+        </programlisting>
+       The resulting shell will have pid 1 and will see no network interfaces.
+       After re-mounting /proc in that shell,
+        <programlisting>
+          mount -t proc proc /proc
+        </programlisting>
+       ps output will show there are no other processes in the namespace.
+        -->
+        새로운 네트워크, PID, 마운트 네임스페이스 내에 쉘을 실행하려면, 아래처럼 하면 된다.
+        <programlisting>
+          lxc-unshare -s "NETWORK|PID|MOUNT" /bin/bash
+        </programlisting>
+        그 결과 생긴 쉘은 1번 pid를 갖는다. 그리고 네트워크 인터페이스는 없다.
+        이 쉘에서 아래처럼  /proc을 다시 마운트하고
+        <programlisting>
+          mount -t proc proc /proc
+        </programlisting>
+        ps 명령어를 입력하면, 네임스페이스 내에서 다른 프로세스들은 보이지 않을 것이다.
+      </para>
+      <para>
+        <!--
+        To spawn a shell in a new network, pid, mount, and hostname
+        namespace.
+        <programlisting>
+          lxc-unshare -s "NETWORK|PID|MOUNT|UTSNAME" -M -H slave -i veth1 /bin/bash
+        </programlisting>
+        -->
+        새로운 네트워크, PID, 마운트 그리고 호스트 이름(UTS) 네임스페이스 내에 쉘을 실행하려면, 아래처럼 하면 된다.
+        <programlisting>
+          lxc-unshare -s "NETWORK|PID|MOUNT|UTSNAME" -M -H slave -i veth1 /bin/bash
+        </programlisting>
+
+        <!--
+       The resulting shell will have pid 1 and will see two network
+       interfaces (lo and veth1).  The hostname will be "slave" and
+       /proc will have been remounted.  ps output will show there are
+       no other processes in the namespace.
+        -->
+        그 결과 생긴 쉘은 1번 pid를 갖는다. 그리고 2개의 네트워크 인터페이스(lo와 veth1)를 갖는다. 호스트 이름은 "slave"이고, /proc은 다시 마운트 된다.
+        ps 명령어를 입력하면, 네임스페이스 내에서 다른 프로세스들은 보이지 않을 것이다.
+      </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-user-nic.sgml.in b/doc/ko/lxc-user-nic.sgml.in
new file mode 100644 (file)
index 0000000..9a3b2d0
--- /dev/null
@@ -0,0 +1,208 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Serge Hallyn <serge.hallyn@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-user-nic</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-user-nic</refname>
+
+    <refpurpose>
+      <!--
+      Create and attach a nic to another network namespace.
+      -->
+      NIC 를 생성하여 다른 네임스페이스에 붙이기
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-user-nic</command>
+      <arg choice="req"><replaceable>pid</replaceable></arg>
+      <arg choice="req"><replaceable>type</replaceable></arg>
+      <arg choice="req"><replaceable>bridge</replaceable></arg>
+      <arg choice="opt"><replaceable>nicname</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-user-nic</command> is a setuid-root program with which
+      unprivileged users may create network interfaces for use by a lxc container.
+      -->
+      <command>lxc-user-nic</command>는 root로 setuid한 프로그램이므로, 특권이 없는 사용자들도 lxc 컨테이너가 사용할 네트워크 인터페이스를 생성할 수 있다.
+    </para>
+    <para>
+      <!--
+      It will consult the configuration file <filename>@LXC_USERNIC_CONF@</filename>
+      to determine the number of interfaces which the calling user is allowed to
+      create, and which bridge he may attach them to.  It tracks the
+      number of interfaces each user has created using the file
+      <filename>@LXC_USERNIC_DB@</filename>.  It ensures that the calling
+      user is privileged over the network namespace to which the interface
+      will be attached.
+      -->
+      이 명령어는 <filename>@LXC_USERNIC_CONF@</filename>을 읽어, 호출한 사용자가 만들수 있는 인터페이스의 수와 어느 브리지에 붙일지 결정한다.
+      각 사용자가 생성한 인터페이스의 수를 <filename>@LXC_USERNIC_DB@</filename> 파일에 기록한다.
+      그리고 호출한 사용자가 인터페이스를 붙인 네트워크 네임스페이스에 특권을 갖게 한다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option><replaceable>pid</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         The process id for the task to whose network namespace the interface
+         should be attached.
+              -->
+            인터페이스가 붙어야하는 네트워크 네임스페이스에 속해있는 프로세스 ID.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option><replaceable>type</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         The network interface type to attach.  Currently only veth is
+         supported.  With this type, two interfaces representing each
+         tunnel endpoint are created.  One endpoint will be attached
+         to the specified bridge, while the other will be passed into
+         the container.
+              -->
+            붙일 네트워크 인터페이스의 형태. 현재는 veth만 지원가능하다. 이 형태에서는 두개의 인터페이스가 각각 터널의 끝지점으로 생성된다. 하나의 끝지점이 특정 브리지에 붙고, 다른 하나는 컨테이너 내부로 넘겨지게 된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option><replaceable>bridge</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         The bridge to which to attach the network interface, for
+         instance <filename>lxcbr0</filename>.
+              -->
+            네트워크 인터페이스를 붙일 프리지. 예를 들어, <filename>lxcbr0</filename> 같이 지정 가능하다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option><replaceable>nicname</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         The desired interface name in the container.  This will be
+         <filename>eth0</filename> if unspecified.
+          -->
+            컨테이너내에서 사용할 인터페이스 이름. 지정하지 않는다면 <filename>eth0</filename>로 된다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+
+    <simpara>
+      <citerefentry>
+       <refentrytitle><command>lxc</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-start</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-usernet</command></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+    </simpara>
+   </refsect1>
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-usernet.sgml.in b/doc/ko/lxc-usernet.sgml.in
new file mode 100644 (file)
index 0000000..7ef81b9
--- /dev/null
@@ -0,0 +1,221 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Ltd. 2013
+
+Authors:
+Serge Hallyn <serge.hallyn@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-usernet</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-usernet</refname>
+
+    <refpurpose>
+      <!--
+      unprivileged user network administration file.
+      -->
+      비특권 사용자의 네트워크 관리용 설정파일
+    </refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <filename>@LXC_USERNIC_CONF@</filename> controls the limits which the
+      program <command>lxc-user-nic</command> places on network interfaces
+      which an unprivileged user may create.
+      -->
+     <filename>@LXC_USERNIC_CONF@</filename>로 비특권 사용자가 <command>lxc-user-nic</command> 명령어로 네트워크 인터페이스를 만들 때, 제한을 걸 수 있다.
+    </para>
+
+    <refsect2>
+      <title><!-- Configuration -->설정</title>
+      <para>
+        <!--
+      This file consists of multiple entries, one per line, of the form:
+          -->
+        이 파일은 아래와 같은 형식의 한 줄로 이루어진 여러 항목들로 구성되어 있다.
+      </para>
+
+      <para>
+      <command>user</command> <command>type</command> <command>bridge</command> <command>number</command>
+      </para>
+      <para>또는 아래의 형식을 사용할 수 있다.</para>
+      <para>
+      <command>@group</command> <command>type</command> <command>bridge</command> <command>number</command>
+      </para>
+      <para>
+        <!--
+      Where
+          -->
+        여기서 각 항목들은 다음과 같은 의미를 가진다.
+      </para>
+
+      <variablelist>
+
+       <varlistentry>
+         <term>
+           <option>user</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             is the username to whom this entry applies.
+              -->
+              이 항목이 적용될 사용자 이름을 가리킨다.
+            </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+            <option>@group</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              is the groupname to which this entry applies.
+                -->
+              이 항목이 적용될 그룹 이름을 가리킨다.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>
+           <option>type</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             is the type of network interface being allowed.  Only veth
+             is currently supported.
+              -->
+              허용되는 네트워크 인터페이스 형태를 가리킨다. veth만 지원된다.
+            </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>bridge</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             is the bridge to which the network interfaces may be attached, for
+             instance <filename>lxcbr0</filename>.
+              -->
+              네트워크 인터페이스들을 붙일 수 있는 브리지를 가리킨다.
+              예를 들어 <filename>lxcbr0</filename>로 지정 가능하다.
+            </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>number</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             is the number or quota of network interfaces of the given type which the
+             given user or group may attach to the given bridge, for instance <filename>2</filename>.
+              -->
+              지정한 사용자 또는 그룹이 지정된 브리지에 붙일 수 있는 지정된 형태의 네트워크 인터페이스 개수를 가리킨다.
+              예를 들어 <filename>2</filename>로 지정 가능하다.
+            </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+
+      <para>
+        <!--
+        Since a user can be specified both by username as well as one or
+        more usergroups, it is possible that several configuration lines
+        enable that user to create network interfaces. In such cases, any
+        interfaces create are counted towards the quotas of the user or group
+        in the order in which they appear in the file. If the quota of one
+        line is full, the rest will be parsed until one is found or the end of
+        the file.
+          -->
+        사용자는 사용자 이름이나 하나 이상의 사용자 그룹을 통해 지정될 수 있으므로, 여러 줄의 설정을 통해 사용자가 네트워크 인터페이스들을 생성할 수 있도록 하는 것이 가능하다.
+        이러한 경우, 인터페이스 생성은 파일 상의 순서대로 사용자 또는 그룹의 사용량에 집계된다.
+        만약 해당 줄에서 할당한 개수가 가득차면, 또다른 설정이 발견되거나 파일의 끝에 도달할 때까지 행을 계속 읽어들인다.
+      </para>
+    </refsect2>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+    <simpara>
+      <citerefentry>
+       <refentrytitle><command>lxc</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+       <refentrytitle><command>lxc-user-nic</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>
+    </simpara>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-usernsexec.sgml.in b/doc/ko/lxc-usernsexec.sgml.in
new file mode 100644 (file)
index 0000000..9568f14
--- /dev/null
@@ -0,0 +1,193 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+Serge Hallyn <serge.hallyn at ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-usernsexec</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-usernsexec</refname>
+
+    <refpurpose>
+      <!--
+      Run a task as root in a new user namespace.
+      -->
+      새로운 사용자 네임스페이스에서 root로 태스크를 실행
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-usernsexec</command>
+      <arg choice="opt">-m <replaceable>uid-map</replaceable></arg>
+      <arg choice="req">-- command</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      <command>lxc-usernsexec</command> can be used to run a task as root
+      in a new user namespace.
+      -->
+      <command>lxc-usernsexec</command>는 새로운 사용자 네임스페이스에서 루트로 태스크를 실행한다.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+
+    <title><!-- Options -->옵션</title>
+
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-m <replaceable>uid-map</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+         The uid map to use in the user namespace.  Each map consists of
+         four colon-separate values.  First a character 'u', 'g' or 'b' to
+         specify whether this map perttains to user ids, group ids, or
+         both; next the first userid in the user namespace;  next the
+         first userid as seen on the host;  and finally the number of
+         ids to be mapped.
+             -->
+            사용자 네임스페이스에서 사용될 uid 맵. 각각의 맵은 4개의 콜론(:)으로 구분된 값들로 구성되어 있다. 첫 번째는 'u', 'g', 'b' 문자로 각각 UID, GID, 또는 UID 및 GID 를 가리킨다. 그 다음은 사용자 네임스페이스 내에서의 UID, 그다음은 호스트의 UID, 그리고 마지막으로 매핑할 ID의 수를 지정한다.
+         </para>
+         <para>
+            <!--
+         More than one map can be specified.  If no map is
+         specified, then by default the full uid and gid ranges granted
+         by /etc/subuid and /etc/subgid will be mapped to the
+         uids and gids starting at 0 in the container.
+              -->
+            맵은 1개 이상도 지정가능하다. 만약 맵이 지정되지 않았다면, 기본값은 /etc/subuid와 /etc/subgid에서 허용된 모든 범위의 uid, gid가 컨테이너 내에서 0번부터 매핑된다.
+         </para>
+         <para>
+            <!--
+         Note that <replaceable>lxc-usernsexec</replaceable> always tries
+         to setuid and setgid to 0 in the namespace.  Therefore uid 0 in
+         the namespace must be mapped.
+              -->
+            <replaceable>lxc-usernsexec</replaceable>는 언제나 0번 setuid와 setgid를 시도한 다는 것에 주의해야 한다. 그러므로 네임스페이스 내에서 uid 0은 매핑이 되어있어야 한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+      <para>
+        <!--
+        To spawn a shell with the full allotted subuids mapped into
+       the container, use
+        <programlisting>
+         lxc-usernsexec
+        </programlisting>
+       To run a different shell than <replaceable>/bin/sh</replaceable>, use
+        <programlisting>
+         lxc-usernsexec &#045;&#045; /bin/bash
+        </programlisting>
+        -->
+        할당된 모든 subuid를 컨테이너에 매핑해서 쉘을 실행하려면,
+        <programlisting>
+         lxc-usernsexec
+        </programlisting>
+        를 사용하면 된다.
+        <replaceable>/bin/sh</replaceable>대신 다른 쉘을 실행하려면,
+        <programlisting>
+         lxc-usernsexec -- /bin/bash
+        </programlisting>
+        를 사용하면 된다.
+      </para>
+      <para>
+        <!--
+       If your user id is 1000, root in a container is mapped to 190000, and
+       you wish to chown a file you own to root in the container, you can use:
+        <programlisting>
+         lxc-usernsexec -m b:0:1000:1 -m b:1:190000:1 &#045;&#045; /bin/chown 1:1 $file
+        </programlisting>
+       This maps your userid to root in the user namespace, and 190000 to uid 1.
+       Since root in the user namespace is privileged over all userids mapped
+       into the namespace, you are allowed to change the file ownership, which
+       you could not do on the host using a simple chown.
+        -->
+        만약 현재 UID가 1000이고, 컨테이너의 root가 190000으로 매핑되어 있으며, 현재 사용자가 소유하고 있는 파일을 컨테이너의 root가 소유하도록 하려면, 아래처럼 하면 된다.
+        <programlisting>
+         lxc-usernsexec -m b:0:1000:1 -m b:1:190000:1 -- /bin/chown 1:1 $file
+        </programlisting>
+        이것은 현재 UID를 사용자 네임스페이스 내에서 root로 하고, 190000을 uid 1로 매핑한다.
+        사용자 네임스페이스의 root는 네임스페이스의 모든 UID에 권한이 있기 때문에, 호스트에서 chown을 사용할 수 없더라도 파일의 소유자를 변경할 수 있다.
+      </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Serge Hallyn <email>serge.hallyn@ubuntu.com</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc-wait.sgml.in b/doc/ko/lxc-wait.sgml.in
new file mode 100644 (file)
index 0000000..396c4d3
--- /dev/null
@@ -0,0 +1,192 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-wait</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-wait</refname>
+
+    <refpurpose>
+      <!--
+      wait for a specific container state
+      -->
+      지정한 컨테이너 상태로 변할 때까지 대기
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-wait</command>
+      <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="req">-s <replaceable>states</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+    <para>
+      <!--
+      <command>lxc-wait</command> waits for a specific container state
+      before exiting, this is useful for scripting.
+      -->
+      <command>lxc-wait</command>는 컨테이너가 지정한 상태로 변할때 까지 대기한다. 이는 스크립트를 위해 유용하다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Options -->옵션</title>
+    <variablelist>
+
+      <varlistentry>
+       <term>
+         <option>-s, --state <replaceable>states</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Specify the container state(s) to wait for. The container
+           states can be ORed to specify several states.
+            -->
+            기다릴 컨테이너 상태를 지정한다.
+            컨테이너 상태들은 OR 기호를 사용하여 여러개를 지정 가능하다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-t, --timeout <replaceable>timeout</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+            <!--
+           Wait timeout seconds for desired state to be reached.
+            -->
+            원하는 상태로 변할 때까지 대기할 최대시간을 timeout 초로 지정한다.
+         </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  &commonoptions;
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+    <variablelist>
+      <varlistentry>
+       <term>lxc-wait -n foo -s RUNNING</term>
+       <listitem>
+       <para>
+          <!--
+         exits when 'RUNNING' is reached.
+          -->
+          foo 컨테이너의 상태가 'RUNNING'일 때까지 대기한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>lxc-wait -n foo -s 'RUNNING|STOPPED'</term>
+       <listitem>
+       <para>
+          <!--
+         exits when 'RUNNING' or 'STOPPED' state is reached.
+          -->
+          foo 컨테이너의 상태가 'RUNNING' 또는 'STOPPED'으로 변할때까지 대기한다.
+       </para>
+       </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Diagnostic -->진단</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>The container was not found</term>
+        <listitem>
+          <para>
+            <!--
+           The specified container was not created before with
+           the <command>lxc-create</command> command.
+            -->
+            지정한 컨테이너가  <command>lxc-create</command>로 생성된 적이 없다.
+            컨테이너가 존재하지 않는다.
+          </para>
+        </listitem>
+      </varlistentry>
+
+
+    </variablelist>
+
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc.conf.sgml.in b/doc/ko/lxc.conf.sgml.in
new file mode 100644 (file)
index 0000000..21a4fb7
--- /dev/null
@@ -0,0 +1,193 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Ltd. 2014
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc.conf</refname>
+
+    <refpurpose>
+      <!--
+      Configuration files for LXC.
+      -->
+      LXC 설정파일
+    </refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      LXC configuration is split in two parts. Container configuration
+      and system configuration.
+      -->
+      LXC 설정파일은 컨테이너 설정과 시스템 설정의 2부분으로 나뉜다.
+    </para>
+
+    <refsect2>
+      <title><!-- Container configuration -->컨테이너 설정</title>
+      <para>
+        <!--
+          The container configuration is held in the
+          <filename>config</filename> stored in the container's
+          directory.
+          -->
+        컨테이너 설정은 컨테이너 디렉토리의 <filename>config</filename>로 설정한다.
+      </para>
+
+      <para>
+        <!--
+          A basic configuration is generated at container creation time
+          with the default's recommended for the chosen template as well
+          as extra default keys coming from the
+          <filename>default.conf</filename> file.
+          -->
+        기본 설정은 컨테이너 생성 시간에 템플릿이 제공해 주는 설정과 <filename>default.conf</filename> 파일에 있는 추가 설정들로 생성된다.
+      </para>
+
+      <para>
+        <!--
+          That <filename>default.conf</filename> file is either located
+          at <filename>@LXC_DEFAULT_CONFIG@</filename> or for
+          unprivileged containers at
+          <filename>~/.config/lxc/default.conf</filename>.
+          -->
+        <filename>default.conf</filename> 파일은 <filename>@LXC_DEFAULT_CONFIG@</filename>에 위치하고 있다.
+        비특권 컨테이너의 경우에는 <filename>~/.config/lxc/default.conf</filename>에 위치하고 있다.
+      </para>
+
+      <para>
+        <!--
+          Details about the syntax of this file can be found in:
+          <citerefentry>
+            <refentrytitle><command>lxc.container.conf</command></refentrytitle>
+            <manvolnum>5</manvolnum>
+          </citerefentry>
+          -->
+        이 파일의 자세한 사용법은 아래를 참고하면 된다.
+        <citerefentry>
+          <refentrytitle><command>lxc.container.conf</command></refentrytitle>
+          <manvolnum>5</manvolnum>
+        </citerefentry>
+      </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- System configuration -->시스템 설정</title>
+      <para>
+        <!--
+          The system configuration is located at
+          <filename>@LXC_GLOBAL_CONF@</filename> or
+          <filename>~/.config/lxc/lxc.conf</filename> for unprivileged
+          containers.
+          -->
+        시스템 설정은 <filename>@LXC_GLOBAL_CONF@</filename>에 위치하고 있다. 비특권 컨테이너의 경우는 <filename>~/.config/lxc/lxc.conf</filename>에 위치하고 있다.
+      </para>
+
+      <para>
+        <!--
+          This configuration file is used to set values such as default
+          lookup paths and storage backend settings for LXC.
+          -->
+        이 설정파일은 LXC 기본 경로 및 저장소 백엔드 설정과 같은 값들을 설정할 때 사용한다.
+      </para>
+
+      <para>
+        <!--
+          Details about the syntax of this file can be found in:
+          <citerefentry>
+            <refentrytitle><command>lxc.system.conf</command></refentrytitle>
+            <manvolnum>5</manvolnum>
+          </citerefentry>
+          -->
+        이 파일의 자세한 사용법은 아래를 참고하면 된다.
+        <citerefentry>
+          <refentrytitle><command>lxc.system.conf</command></refentrytitle>
+          <manvolnum>5</manvolnum>
+        </citerefentry>
+      </para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+    <simpara>
+      <citerefentry>
+        <refentrytitle><command>lxc</command></refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc.container.conf</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc.system.conf</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc-usernet</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>
+    </simpara>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc.container.conf.sgml.in b/doc/ko/lxc.container.conf.sgml.in
new file mode 100644 (file)
index 0000000..90b36c2
--- /dev/null
@@ -0,0 +1,2650 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc.container.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc.container.conf</refname>
+
+    <refpurpose>
+      <!--
+      LXC container configuration file
+      -->
+      LXC 컨테이너 설정파일
+    </refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      The linux containers (<command>lxc</command>) are always created
+      before being used. This creation defines a set of system
+      resources to be virtualized / isolated when a process is using
+      the container. By default, the pids, sysv ipc and mount points
+      are virtualized and isolated. The other system resources are
+      shared across containers, until they are explicitly defined in
+      the configuration file. For example, if there is no network
+      configuration, the network will be shared between the creator of
+      the container and the container itself, but if the network is
+      specified, a new network stack is created for the container and
+      the container can no longer use the network of its ancestor.
+      -->
+      linux 컨테이너(<command>lxc</command>)는 항상 사용하기 전에 생성된다.
+      생성 작업은 가상화할 자원 및 컨테이너 내에서 실행되는 프로세스로부터 고립할 시스템 자원들을 정의하는 것이다.
+      기본적으로 pid, sysv ipc, 마운트 포인트가 가상화되고 고립된다. 명시적으로 설정파일에서 정의되기 전까지, 다른 시스템 자원들은 컨테이너 간에 공유된다. 예를 들어, 네트워크 설정이 되어 있지 않다면, 컨테이너 생성한 쪽과 컨테이너 간에 네트워크를 서로 공유할 것이다. 그러나 네트워크가 지정이되었다면, 컨테이너를 위해 새로운 네트워크 스택이 생성된다. 그리고 컨테이너는 더이상 그를 생성한 쪽과 네트워크를 공유하지 않는다.
+    </para>
+
+    <para>
+      <!--
+      The configuration file defines the different system resources to
+      be assigned for the container. At present, the utsname, the
+      network, the mount points, the root file system, the user namespace,
+      and the control groups are supported.
+      -->
+      설정파일은 컨테이너에 할당될 시스템 자원들을 정의한다. 현재는 utsname, 네트워크, 마운트포인트, 루트 파일시스템, 사용자 네임스페이스 그리고 컨트롤 그룹이 지원된다.
+    </para>
+
+    <para>
+      <!--
+      Each option in the configuration file has the form <command>key
+      = value</command> fitting in one line. The '#' character means
+      the line is a comment. List options, like capabilities and cgroups
+      options, can be used with no value to clear any previously
+      defined values of that option.
+      -->
+      설정파일의 옵션은 <command>key = value</command>의 한 줄로 이루어져 있다.
+      '#' 문자를 앞에 붙여 주석임을 나타낼 수 있다. capability와 cgroup 옵션과 같은 리스트 옵션들은, 값을 지정하지 않고 사용할 수 있다. 값이 지정되지 않은 경우 이전에 설정했던 모든 값들을 지운다.
+    </para>
+
+    <refsect2>
+      <title><!-- Configuration -->설정</title>
+      <para>
+        <!--
+       In order to ease administration of multiple related containers, it
+       is possible to have a container configuration file cause another
+       file to be loaded.  For instance, network configuration
+       can be defined in one common file which is included by multiple
+       containers.  Then, if the containers are moved to another host,
+       only one file may need to be updated.
+        -->
+        연관된 컨테이너들을 쉽게 관리하기 위해서, 컨테이너 설정파일은 다른 파일을 불러올 수 있다. 예를 들어서, 네트워크 설정은 여러 컨테이너들을 위해 공통된 하나의 파일로 정의될 수 있다. 그리고 만약 컨테이너들이 다른 호스트로 이동된다면, 해당 파일 하나만 수정하면 된다.
+      </para>
+
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.include</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the file to be included.  The included file must be
+             in the same valid lxc configuration file format.
+              -->
+              include할 파일을 지정한다.
+              include할 파일은 lxc 설정파일의 형식에 부합하여야 한다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Architecture -->아키텍처</title>
+      <para>
+        <!--
+       Allows one to set the architecture for the container. For example,
+       set a 32bits architecture for a container running 32bits
+       binaries on a 64bits host. That fixes the container scripts
+       which rely on the architecture to do some work like
+       downloading the packages.
+        -->
+        컨테이너에 아키텍처를 지정할 수 있다. 예를 들어, 64비트 호스트에서 32비트 바이너리를 실행하는 컨테이너라면 32비트 아키텍처로 지정할 수 있다. 패키지를 다운로드 받는 등의 작업을 수행하는 아키텍처에 의존적인 컨테이너 스크립트가 잘 동작할 수 있도록 해준다.
+      </para>
+
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.arch</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the architecture for the container.
+              -->
+              컨테이너의 아키텍처를 지정한다.
+           </para>
+           <para>
+              <!--
+             Valid options are
+             <option>x86</option>,
+             <option>i686</option>,
+             <option>x86_64</option>,
+             <option>amd64</option>
+              -->
+              가능한 옵션은 아래와 같다.
+             <option>x86</option>,
+             <option>i686</option>,
+             <option>x86_64</option>,
+             <option>amd64</option>
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Hostname -->호스트 이름</title>
+      <para>
+        <!--
+       The utsname section defines the hostname to be set for the
+       container. That means the container can set its own hostname
+       without changing the one from the system. That makes the
+       hostname private for the container.
+        -->
+        utsname 섹션은 컨테이너 내에서 설정할 호스트 이름을 정의한다. 컨테이너는        시스템의 호스트 이름을 변경하지 않고도 자신의 호스트 이름을 변경할 수 있다. 즉, 컨테이너마다 호스트 이름을 설정할 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.utsname</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the hostname for the container
+              -->
+              컨테이너의 호스트 이름을 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Halt signal -->종료 시그널</title>
+      <para>
+        <!--
+        Allows one to specify signal name or number, sent by lxc-stop to the
+        container's init process to cleanly shutdown the container. Different
+        init systems could use different signals to perform clean shutdown
+        sequence. This option allows the signal to be specified in kill(1)
+        fashion, e.g. SIGPWR, SIGRTMIN+14, SIGRTMAX-10 or plain number. The
+        default signal is SIGPWR.
+          -->
+        lxc-stop이 컨테이너를 깨끗이 종료를 시키기 위해서 보낼 시그널의 이름이나 숫자를 지정할 수 있다.
+        init 시스템마다 깨끗한 종료를 위해 각기 다른 시그널을 사용할 수 있다.
+        이 옵션은 kill(1)에서 사용하는 것 처럼 시그널을 지정할 수 있다. 예를 들어 SIGPWR, SIGRTMIN+14, SIGRTMAX-10 또는 숫자를 지정할 수 있다. 기본 시그널은 SIGPWR이다.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.haltsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              specify the signal used to halt the container
+              -->
+              컨테이너를 종료할 때 사용할 시그널을 지정한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Reboot signal -->재부팅 시그널</title>
+      <para>
+        <!--
+        Allows one to specify signal name or number, sent by lxc-stop to
+        reboot the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGTERM, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGINT.
+          -->
+        lxc-stop이 컨테이너를 재부팅하기 위해 보낼 시그널의 이름이나 숫자를 지정할 수 있다.
+        이 옵션은 kill(1)에서 사용하는 것 처럼 시그널을 지정할 수 있다. 예를 들어 SIGINT, SIGRTMIN+14, SIGRTMAX-10 또는 숫자를 지정할 수 있다. 기본 시그널은 SIGINT이다.
+          </para>
+          <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.rebootsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              specify the signal used to reboot the container
+                -->
+              컨테이너를 재부팅할 때 사용할 시그널을 지정한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Stop signal -->강제종료 시그널</title>
+      <para>
+        <!--
+        Allows one to specify signal name or number, sent by lxc-stop to forcibly
+        shutdown the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGKILL.
+          -->
+        lxc-stop이 컨테이너를 강제종료하기 위해 보낼 시그널의 이름이나 숫자를 지정할 수 있다.
+        이 옵션은 kill(1)에서 사용하는 것 처럼 시그널을 지정할 수 있다. 예를 들>어 SIGKILL, SIGRTMIN+14, SIGRTMAX-10 또는 숫자를 지정할 수 있다. 기본 시그널은 SIGKILL이다.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.stopsignal</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+                  specify the signal used to stop the container
+                -->
+              컨테이너를 강제종료할 때 사용할 시그널을 지정한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Init command -->Init 명령어</title>
+      <para>
+        <!--
+        Sets the command to use as the init system for the containers.
+
+        This option is ignored when using lxc-execute.
+
+        Defaults to: /sbin/init
+          -->
+        컨테이너의 init으로 사용할 명령어를 설정한다.
+        이 옵션은 lxc-execute을 사용할 때는 무시된다.
+        기본값은 /sbin/init이다.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.init_cmd</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+                  Absolute path from container rootfs to the binary to use as init.
+                -->
+              init으로 사용할 바이저리의 컨테이너 루트 파일시스템에서의 절대 경로.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Init ID -->Init이 사용할 ID</title>
+      <para>
+        <!--
+        Sets the UID/GID to use for the init system, and subsequent command, executed by lxc-execute.
+        -->
+        lxc-execute가 실행하는 컨테이너의 init 및 명령어가 사용할 UID/GID를 지정한다.
+
+        <!--
+        These options are only used when lxc-execute is started in a private user namespace.
+        -->
+        이 옵션들은 lxc-execute가 사용자 네임스페이스 안에서 실행될 때만 적용된다.
+
+        <!--
+        Defaults to: UID(0), GID(0)
+        -->
+        기본 값: UID(0), GID(0)
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.init_uid</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              UID to use within a private user namesapce for init.
+                -->
+              init이 사용자 네임스페이스 안에서 사용할 UID.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.init_gid</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              GID to use within a private user namesapce for init.
+                -->
+              init이 사용자 네임스페이스 안에서 사용할 GID.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Ephemeral -->임시 컨테이너</title>
+      <para>
+        <!--
+        Allows one to specify whether a container will be destroyed on shutdown.
+          -->
+        컨테이너가 종료될 때, 해당 컨테이너를 제거할지 여부를 지정할 수 있다.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.ephemeral</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              The only allowed values are 0 and 1. Set this to 1 to destroy a
+              container on shutdown.
+                -->
+              지정 가능한 값은 0 또는 1이다. 1로 설정하면, 컨테이너를 종료할 때 해당 컨테이너를 제거한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Network -->네트워크</title>
+      <para>
+        <!--
+       The network section defines how the network is virtualized in
+       the container. The network virtualization acts at layer
+       two. In order to use the network virtualization, parameters
+       must be specified to define the network interfaces of the
+       container. Several virtual interfaces can be assigned and used
+       in a container even if the system has only one physical
+       network interface.
+        -->
+        네트워크 섹션은 어떻게 네트워크를 컨테이너 내에서 가상화할지를 정의한다.
+        네트워크 가상화는 2개의 계층으로 동작한다.
+        네트워크 가상화를 위해서, 컨테이너의 네트워크 인터페이스가 인수로 지정되어야 한다. 시스템이 하나의 물리적인 네트워크 인터페이스를 갖고 있어도, 컨테이너 내에서 여러개의 가상화 인터페이스들을 사용할 수 있다.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.network</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              may be used without a value to clear all previous network options.
+              -->
+              값을 지정하지 않고 사용하여 이전에 설정했던 모든 네트워크 옵션들을 초기화할 수 있다.
+            </para>
+          </listitem>
+        </varlistentry>
+       <varlistentry>
+         <term>
+           <option>lxc.network.type</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify what kind of network virtualization to be used
+             for the container. Each time
+             a <option>lxc.network.type</option> field is found a new
+             round of network configuration begins. In this way,
+             several network virtualization types can be specified
+             for the same container, as well as assigning several
+             network interfaces for one container. The different
+             virtualization types can be:
+              -->
+              컨테이너가 어떤 종류의 네트워크 가상화를 사용할지 지정한다.
+              <option>lxc.network.type</option> 필드부터 새로운 네트워크 설정이 시작된다. 이 방법으로 여러개의 네트워크 가상화 형태를 같은 컨테이너에 지정할 수 있다. 그리고 여러개의 네트워크 인터페이스를 하나의 컨테이너에 지정할 수도 있다.
+              지정 가능한 형태는 아래와 같다.
+           </para>
+
+           <para>
+              <!--
+             <option>none:</option> will cause the container to share
+             the host's network namespace.  This means the host
+             network devices are usable in the container.  It also
+             means that if both the container and host have upstart as
+             init, 'halt' in a container (for instance) will shut down the
+             host.
+              -->
+              <option>none:</option> 호스트의 네트워크 네임스페이스를 공유한다. 이렇게 하면 호스트의 네트워크 장치를 컨테이너 내에서 사용가능하다.
+              컨테이너와 호스트 둘다 init에서 upstart를 사용하는 경우, (예를 들어) 컨테이너에서 'halt'를 하면, 호스트의 것도 종료된다.
+           </para>
+
+           <para>
+              <!--
+             <option>empty:</option> will create only the loopback
+             interface.
+              -->
+             <option>empty:</option>는 루프백 인터페이스만 생성한다.
+           </para>
+
+            <para>
+              <!--
+              <option>veth:</option> a virtual ethernet pair
+              device is created with one side assigned to the container
+              and the other side attached to a bridge specified by
+              the <option>lxc.network.link</option> option.
+              If the bridge is not specified, then the veth pair device
+              will be created but not attached to any bridge.
+              Otherwise, the bridge has to be created on the system
+              before starting the container.
+              <command>lxc</command> won't handle any
+              configuration outside of the container.
+              By default, <command>lxc</command> chooses a name for the
+              network device belonging to the outside of the
+              container, but if you wish to handle
+              this name yourselves, you can tell <command>lxc</command>
+              to set a specific name with
+              the <option>lxc.network.veth.pair</option> option (except for
+              unprivileged containers where this option is ignored for security
+              reasons).
+              -->
+              <option>veth:</option> 한 쪽은 컨테이너로, 다른 한쪽은 <option>lxc.network.link</option> 옵션으로 지정한 브리지로 붙은 가상 이더넷(veth) 장치 쌍을 생성한다.
+              만약 브리지가 지정되지 않았다면, 어떤 브리지에도 붙지 않은  veth 장치 쌍을 만든다. 브리지는 컨테이너 시작전에 시스템에서 생성해야 한다.
+              <command>lxc</command>는 컨테이너 이외의 설정에 대해서는 다루지 않는다. 기본값으로 <command>lxc</command>는 컨테이너 바깥에 속할 네트워크 디바이스의 이름을 정해준다. 이름을 변경하기 원한다면, <command>lxc</command>가 지정한 이름으로 설정하도록 <option>lxc.network.veth.pair</option> 옵션을 사용하여야 한다. (비특권 컨테이너는 불가능하다. 이 옵션은 보안상의 이유로 무시될 것이다)
+            </para>
+
+           <para>
+              <!--
+             <option>vlan:</option> a vlan interface is linked with
+             the interface specified by
+             the <option>lxc.network.link</option> and assigned to
+             the container. The vlan identifier is specified with the
+             option <option>lxc.network.vlan.id</option>.
+              -->
+              <option>vlan:</option> vlan 인터페이스는 <option>lxc.network.link</option>로 지정한 인터페이스에 연결되고, 컨테이너로 할당된다. vlan의 식별자는 <option>lxc.network.vlan.id</option> 옵션으로 지정한다.
+           </para>
+
+           <para>
+              <!--
+             <option>macvlan:</option> a macvlan interface is linked
+             with the interface specified by
+             the <option>lxc.network.link</option> and assigned to
+             the container.
+             <option>lxc.network.macvlan.mode</option> specifies the
+             mode the macvlan will use to communicate between
+             different macvlan on the same upper device. The accepted
+              modes are <option>private</option>, <option>vepa</option>,
+              <option>bridge</option> and <option>passthru</option>.
+             In <option>private</option> mode, the device never
+              communicates with any other device on the same upper_dev (default).
+              In <option>vepa</option> mode, the new Virtual Ethernet Port
+             Aggregator (VEPA) mode, it assumes that the adjacent
+             bridge returns all frames where both source and
+             destination are local to the macvlan port, i.e. the
+             bridge is set up as a reflective relay.  Broadcast
+             frames coming in from the upper_dev get flooded to all
+             macvlan interfaces in VEPA mode, local frames are not
+              delivered locally. In <option>bridge</option> mode, it
+             provides the behavior of a simple bridge between
+             different macvlan interfaces on the same port. Frames
+             from one interface to another one get delivered directly
+             and are not sent out externally. Broadcast frames get
+             flooded to all other bridge ports and to the external
+             interface, but when they come back from a reflective
+             relay, we don't deliver them again.  Since we know all
+             the MAC addresses, the macvlan bridge mode does not
+              require learning or STP like the bridge module does. In
+              <option>passthru</option> mode, all frames received by
+              the physical interface are forwarded to the macvlan
+              interface. Only one macvlan interface in <option>passthru</option>
+              mode is possible for one physical interface.
+              -->
+              <option>macvlan:</option> macvlan 인터페이스는 <option>lxc.network.link</option>로 지정한 인터페이스에 연결되고, 컨테이너로 할당된다.
+              <option>lxc.network.macvlan.mode</option>은 같은 상위 디바이스에 있는 다른 macvlan과 통신할 때 사용하는 모드를 지정한다.
+              지정할 수 있는 모드는 <option>private</option>、<option>vepa</option>、<option>bridge</option>、<option>passthru</option>이다.
+              <option>private</option>모드는 디바이스가 같은 상위디바이스의 어떤 장치와도 통신하지 않는다. (기본값)
+              새로운 가상 이더넷 포트 통합모드(Virtual Ethernet Port Aggregator), 즉 <option>vepa</option> 모드는 인접한 브리지가 소스와 목적지가 로컬인 모든 프레임들을 macvlan 포트로 반환한다고 가정한다. 즉,  브리지가 reflective relay로 설정되어 있다는 것이다.
+              상위장치에서 들어오는 브로드캐스트 프레임들은 모든 macvlan 인터페이스에게 보내져버린다.  로컬 프레임들은 로컬로 보내지지 않는다.
+              <option>bridge</option> 모드는 같은 포트의 다른 macvlan 인터페이스 사이에 간단한 브리지를 제공한다.
+              어떤 인터페이스에서 다른 인터페이스로 프레임은 직접 전달된다. 하지만 외부로는 보내지지 않는다.
+              브로드캐스트 프레임들은 모든 다른 브리지 포트들과 외부 인터페이스에 전달된다.
+              그러나 reflective relay로 다시 돌아왔을 때는, 그것들을 다시 전송하지 않는다.
+              모든 MAC 주소를 알기 때문에, macvlan 브리지모드는 브리지 모듈처럼 학습이나 STP를 요구하지 않는다.
+              <option>passthru</option>모드는 물리 인터페이스로 부터 받은 모든 프레임들을 macvlan 인터페이스로 포워딩한다.
+              <option>passthru</option>모드만이 하나의 물리 인터페이스를 설정하는게 가능하다.
+           </para>
+
+           <para>
+              <!--
+             <option>phys:</option> an already existing interface
+             specified by the <option>lxc.network.link</option> is
+             assigned to the container.
+              -->
+              <option>phys:</option> <option>lxc.network.link</option>로 지정한 이미 존재하는 인터페이스를 컨테이너로 할당된다.
+           </para>
+         </listitem>
+         </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.flags</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify an action to do for the
+             network.
+              -->
+              네트워크에 수행할 작업을 지정한다.
+           </para>
+
+           <para>
+              <!--
+              <option>up:</option> activates the interface.
+              -->
+              <option>up:</option> 인터페이스를 활성화시킨다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.link</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the interface to be used for real network
+             traffic.
+              -->
+              실제 네트워크 트래픽에 사용할 인터페이스를 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.mtu</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the maximum transfer unit for this interface.
+              -->
+              해당 인터페이스의 최대 전송 단위(MTU)를 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.name</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             the interface name is dynamically allocated, but if
+             another name is needed because the configuration files
+             being used by the container use a generic name,
+             eg. eth0, this option will rename the interface in the
+             container.
+             -->
+              인터페이스 이름은 동적으로 할당된다.
+              그러나, 컨테이너가 일반적으로 사용하는 이름과 다른 이름이 필요하다면, (예: eth0) 이 옵션은 컨테이너 내에 있는 인터페이스의 이름을 지정한 것으로 변경할 수 있다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.hwaddr</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             the interface mac address is dynamically allocated by
+             default to the virtual interface, but in some cases,
+             this is needed to resolve a mac address conflict or to
+             always have the same link-local ipv6 address.
+             Any "x" in address will be replaced by random value,
+             this allows setting hwaddr templates.
+              -->
+              가상 인터페이스의 MAC 주소는 기본적으로 동적 할당된다. 그러나 몇몇가지 이유로 MAC 주소 충돌 문제를 해결하거나, 언제나 같은 링크 로컬 IPv6 주소가 필요하다면, 이 옵션이 필요하다.
+              주소의 "x"는 무작위한 값으로 바뀐다. 템플릿에서 하드웨어 주소를 설정하는데 유용하다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.ipv4</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the ipv4 address to assign to the virtualized
+             interface. Several lines specify several ipv4 addresses.
+             The address is in format x.y.z.t/m,
+             eg. 192.168.1.123/24.The broadcast address should be
+             specified on the same line, right after the ipv4
+             address.
+              -->
+              가상 인터페이스에서 사용할 IPv4 주소를 지정한다.
+              여러 행으로 여러개의 IPv4 주소를 지정할 수 있다.
+              주소의 형식은 x.y.z.t/m으로, 예를 들어 192.168.1.123/24이다. 브로드 캐스트 주소는 같은 행의 주소 바로 오른쪽에 지정하면 된다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.ipv4.gateway</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the ipv4 address to use as the gateway inside the
+             container. The address is in format x.y.z.t, eg.
+             192.168.1.123.
+
+             Can also have the special value <option>auto</option>,
+             which means to take the primary address from the bridge
+             interface (as specified by the
+             <option>lxc.network.link</option> option) and use that as
+             the gateway. <option>auto</option> is only available when
+             using the <option>veth</option> and
+             <option>macvlan</option> network types.
+              -->
+              컨테이너 내부에서 게이트웨이로 사용할 IPv4 주소를 지정한다.
+              주소 형식은 x.y.z.t로, 예를 들면 192.168.1.123이다.
+
+              <option>auto</option>라는 특별한 값을 지정할 수있다.
+              이것은 (<option>lxc.network.link</option> 에서 지정된) 브리지 인터페이스의 첫번째 주소를 가져와 게이트 주소로 사용한다.
+              <option>auto</option>는 네트워크 형태가 <option>veth</option>나 <option>macvlan</option>일 때만 지정 가능하다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.ipv6</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the ipv6 address to assign to the virtualized
+             interface. Several lines specify several ipv6 addresses.
+             The address is in format x::y/m,
+             eg. 2003:db8:1:0:214:1234:fe0b:3596/64
+              -->
+              가상 인터페이스에서 사용할 IPv6 주소를 지정한다.
+              여러 행으로 여러개의 IPv6 주소를 지정할 수 있다.
+              주소의 형식은 x::y/m으로, 예를 들어 2003:db8:1:0:214:1234:fe0b:3596/64이다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.ipv6.gateway</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the ipv6 address to use as the gateway inside the
+             container. The address is in format x::y,
+             eg. 2003:db8:1:0::1
+
+             Can also have the special value <option>auto</option>,
+             which means to take the primary address from the bridge
+             interface (as specified by the
+             <option>lxc.network.link</option> option) and use that as
+             the gateway. <option>auto</option> is only available when
+             using the <option>veth</option> and
+             <option>macvlan</option> network types.
+              -->
+              컨테이너 내부에서 게이트웨이로 사용할 IPv4 주소를 지정한다.
+              주소 형식은 x::y로, 예를 들면 2003:db8:1:0::1이다.
+
+              <option>auto</option>라는 특별한 값을 지정할 수있다.
+              이것은 (<option>lxc.network.link</option> 에서 지정된) 브리지 인터페이스의 첫번째 주소를 가져와 게이트 주소로 사용한다.
+<option>auto</option>는 네트워크 형태가 <option>veth</option>나 <option>macvlan</option>일 때만 지정 가능하다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.script.up</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             add a configuration option to specify a script to be
+             executed after creating and configuring the network used
+             from the host side. The following arguments are passed
+             to the script: container name and config section name
+             (net) Additional arguments depend on the config section
+             employing a script hook; the following are used by the
+             network system: execution context (up), network type
+             (empty/veth/macvlan/phys), Depending on the network
+             type, other arguments may be passed:
+             veth/macvlan/phys. And finally (host-sided) device name.
+              -->
+              네트워크를 설정하고 생성한 후에 호스트 쪽에서 실행되는 스크립트를 지정한다.
+              다음 인수들이 스크립트에 넘겨진다 : 컨테이너 이름, 설정 섹션 이름(net). 그 후 인수는 훅 스크립트을 사용하는 설정 섹션에 달려있다. 다음 인수들은 네트워크 시스템에 의해 사용되어진다 : 실행 컨텍스트(up), 네트워크 형태(empty/veth/macvlan/phys). 네트워크 형태에 따라서 다음 인수들이 넘겨진다 : veth/macvlan/phys의 경우, (호스트 쪽의) 장치 이름.
+            </para>
+           <para>
+              <!--
+             Standard output from the script is logged at debug level.
+             Standard error is not logged, but can be captured by the
+             hook redirecting its standard error to standard output.
+              -->
+              스크립트의 표준출력은 debug 수준 로그로 납겨진다.
+              표준 에러는 로그로 남겨지지는 않지만, 표준 에러를 표준 출력으로 리다이렉션하여 로그로 남길 수 있다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.network.script.down</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             add a configuration option to specify a script to be
+             executed before destroying the network used from the
+             host side. The following arguments are passed to the
+             script: container name and config section name (net)
+             Additional arguments depend on the config section
+             employing a script hook; the following are used by the
+             network system: execution context (down), network type
+             (empty/veth/macvlan/phys), Depending on the network
+             type, other arguments may be passed:
+             veth/macvlan/phys. And finally (host-sided) device name.
+              -->
+              네트워크를 제거한 후에 호스트 쪽에서 실행되는 스크립트를 지정한다.
+              다음 인수들이 스크립트에 넘겨진다 : 컨테이너 이름, 설정 섹션 이름(net). 그 후 인수는 훅 스크립트을 사용하는 설정 섹션에 달려있다.
+              다음 인수들은 네트워크 시스템에 의해 사용되어진다 : 실행 컨텍스트(down), 네트워크 형태(empty/veth/macvlan/phys). 네트워크 형태에 따라서 다음 인수들이 넘겨진다 : veth/macvlan/phys의 경우, (호스트 쪽의) 장치 이름.
+            </para>
+           <para>
+              <!--
+             Standard output from the script is logged at debug level.
+             Standard error is not logged, but can be captured by the
+             hook redirecting its standard error to standard output.
+              -->
+              스크립트의 표준출력은 debug 수준 로그로 납겨진다.
+              표준 에러는 로그로 남겨지지는 않지만, 표준 에러를 표준 출력으로 리다이렉션하여 로그로 남길 수 있다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+
+    </refsect2>
+
+    <refsect2>
+      <title><!-- New pseudo tty instance (devpts) -->새로운 pseudo tty 인스턴스(devpts)</title>
+      <para>
+        <!--
+       For stricter isolation the container can have its own private
+       instance of the pseudo tty.
+        -->
+        강한 고립을 위해 컨테이너는 자기자신만의 pseudo tty를 가질 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.pts</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             If set, the container will have a new pseudo tty
+             instance, making this private to it. The value specifies
+              the maximum number of pseudo ttys allowed for a pts
+              instance (this limitation is not implemented yet).
+              -->
+              만약 지정되었다면, 컨테이너는 새 pseudo tty 인스턴스를 갖는다. 그리고 이것을 자기자신 전용으로 만든다. 지정하는 값은 pseudo tty의 최대 개수를 지정한다. (이 제한은 아직 구현되지 않았다)
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Container system console -->컨테이너 시스템 콘솔</title>
+      <para>
+        <!--
+       If the container is configured with a root filesystem and the
+       inittab file is setup to use the console, you may want to specify
+       where the output of this console goes.
+        -->
+        컨테이너에 루트 파일시스템이 설정되어 있고 inittab 파일에 콘솔을 사용하는 것이 설정되어 있다면, 콘솔의 출력을 어디로 할지 지정할 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.console.logfile</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify a path to a file where the console output will
+             be written.
+              -->
+              콘솔의 출력을 쓸 파일의 경로를 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <option>lxc.console</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify a path to a device to which the console will be
+             attached.  The keyword 'none' will simply disable the
+             console.  This is dangerous once if have a rootfs with a
+             console device file where the application can write, the
+             messages will fall in the host.
+              -->
+              콘솔을 붙일 장치의 경로를 지정한다.
+              'none'이라는 값은 단순히 콘솔을 비활성화 시킨다. 만약 응용 프로그램이 쓸 수 있는 콘솔 장치 파일이 루트 파일시스템에 있으면, 메시지가 호스트 쪽에 출력되므로 이 설정은 위험할 수 있다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Console through the ttys -->tty를 통한 콘솔</title>
+      <para>
+        <!--
+       This option is useful if the container is configured with a root
+       filesystem and the inittab file is setup to launch a getty on the
+       ttys. The option specifies the number of ttys to be available for
+       the container. The number of gettys in the inittab file of the
+       container should not be greater than the number of ttys specified
+       in this option, otherwise the excess getty sessions will die and
+       respawn indefinitely giving annoying messages on the console or in
+       <filename>/var/log/messages</filename>.
+        -->
+        컨테이너에 루트 파일시스템이 설정되어 있고 inittab 파일에 tty에서 getty를 실행하는 것이 설정되어 있다면, 이 옵션은 유용하다.
+        이 옵션은 컨테이너에서 사용가능한 tty의 개수를 지정한다.
+        컨테이너의 inittab 파일에 설정된 getty의 개수는 이 옵션에서 정한 tty의 개수보다 크면 안된다. 그렇지 않으면 초과된 getty 세션은 무한히 죽고 다시 살아나기를 반복하며 콘솔이나 <filename>/var/log/messages</filename>에 계속 메시지를 띄울 것이다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.tty</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the number of tty to make available to the
+             container.
+              -->
+              컨테이너가 만들 수 있는 tty의 개수를 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Console devices location -->콘솔 장치 위치</title>
+      <para>
+        <!--
+        LXC consoles are provided through Unix98 PTYs created on the
+       host and bind-mounted over the expected devices in the container.
+       By default, they are bind-mounted over <filename>/dev/console</filename>
+       and <filename>/dev/ttyN</filename>.  This can prevent package upgrades
+       in the guest.  Therefore you can specify a directory location (under
+       <filename>/dev</filename> under which LXC will create the files and
+       bind-mount over them.  These will then be symbolically linked to
+       <filename>/dev/console</filename> and <filename>/dev/ttyN</filename>.
+       A package upgrade can then succeed as it is able to remove and replace
+       the symbolic links.
+        -->
+        LXC 콘솔은 호스트에서 생성된 Unix98 PTY와 컨테이너 내에 바인드 마운트될 장치들을 통해 제공된다. 기본적으로 <filename>/dev/console</filename>와 <filename>/dev/ttyN</filename>를 바인드 마운트 한다. 이것은 게스트에서 패키지 업그레이드를 방해하는 요인이 된다. 그래서 <filename>/dev</filename> 밑에 LXC가 파일을 생성하고 바인드 마운트할 디렉토리의 위치를 따로 지정해 줄 수 있다.
+        그리고 만들어진 파일들은 <filename>/dev/console</filename>와 <filename>/dev/ttyN</filename>에 심볼릭 링크된다.
+        심볼릭 링크들은 삭제하거나 대체하는 것이 가능하므로 패키지 업그레이드는 성공적으로 이루어질 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.devttydir</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify a directory under <filename>/dev</filename>
+             under which to create the container console devices.
+              -->
+              컨테이너 콘솔 장치를 생성할 <filename>/dev</filename> 밑의 디렉토리를 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- /dev directory -->/dev 디렉토리</title>
+      <para>
+        <!--
+       By default, lxc creates a few symbolic links (fd,stdin,stdout,stderr)
+       in the container's <filename>/dev</filename> directory but does not
+       automatically create device node entries. This allows the container's
+       <filename>/dev</filename> to be set up as needed in the container
+       rootfs.  If lxc.autodev is set to 1, then after mounting the container's
+       rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
+       (limited to 500k) and fill in a minimal set of initial devices.
+        This is generally required when starting a container containing
+        a "systemd" based "init" but may be optional at other times.  Additional
+        devices in the containers /dev directory may be created through the
+        use of the <option>lxc.hook.autodev</option> hook.
+        -->
+        기본적으로 lxc는 약간의 심볼릭 링크(fd, stdin, stdout, stderr)를 컨테이너의 <filename>/dev</filename> 디렉토리에 생성한다. 그러나 자동으로 장치 노드 항목들을 생성해주지 않는다. 컨테이너의 루트 파일시스템에서 필요로하는 <filename>/dev</filename>를 생성할 수 있게 하는 것이다. lxc.autodev가 1로 지정되었다면, 컨테이너 루트 파일시스템을 마운트 한 후, LXC가 <filename>/dev</filename> 밑에 새로운 tmpfs(최대 500k)를 마운트 해준다. 그리고 최소한의 장치만을 채워준다.
+        이것은 "systemd" 기반의 "init" 환경의 컨테이너를 시작할 때 일반적으로 필요하지만, 다른 환경의 경우는 선택적인 요소이다.
+         컨테이너의 부가적인 장치들은 <option>lxc.hook.autodev</option> 훅 스크립트를 사용하여 /dev 디렉토리에 생성할 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.autodev</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+              Set this to 0 to stop LXC from mounting and populating a minimal
+              <filename>/dev</filename> when starting the container.
+              -->
+              컨테이너 시작시 <filename>/dev</filename>을 마운트하고 최소한으로  <filename>/dev</filename>를 구성할지 지정한다. 0이면 해당 동작을 수행하지 않는다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Enable kmsg symlink -->kmsg 심볼릭링크 사용</title>
+      <para>
+        <!--
+        Enable creating /dev/kmsg as symlink to /dev/console.  This defaults to 0.
+        -->
+        /dev/console에 대한 심볼릭 링크로 /dev/kmsg를 생성한다.
+      </para>
+      <variablelist>
+    <varlistentry>
+      <term>
+        <option>lxc.kmsg</option>
+      </term>
+      <listitem>
+        <para>
+          <!--
+          Set this to 1 to enable /dev/kmsg symlinking.
+          -->
+          이것을 1로 지정하면 /dev/kmsg 심볼릭링크를 사용한다.
+        </para>
+      </listitem>
+    </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Mount points -->마운트 포인트</title>
+      <para>
+        <!--
+       The mount points section specifies the different places to be
+       mounted. These mount points will be private to the container
+       and won't be visible by the processes running outside of the
+       container. This is useful to mount /etc, /var or /home for
+       examples.
+        -->
+        마운트 포인트 섹션은 마운트가 될 각각의 장소를 지정한다.
+        이 마운트 포인트들은 컨테이너에서만 보이고 외부에서 실행하는 프로세스들에겐 보이지 않는다.
+        이는 예를 들어  /etc, /var, /home을 마운트할 때 유용하다.
+      </para>
+      <para>
+        <!--
+        NOTE - LXC will generally ensure that mount targets and relative
+        bind-mount sources are properly confined under the container
+        root, to avoid attacks involving over-mounting host directories
+        and files.  (Symbolic links in absolute mount sources are ignored)
+        However, if the container configuration first mounts a directory which
+        is under the control of the container user, such as /home/joe, into
+        the container at some <filename>path</filename>, and then mounts
+        under <filename>path</filename>, then a TOCTTOU attack would be
+        possible where the container user modifies a symbolic link under
+        his home directory at just the right time.
+        -->
+        주의 - 보통 LXC는 마운트 대상과 상대 경로로 된 바인드 마운트 소스들이 컨테이너의 루트 아래에 있도록 보장할 것이다. 이는 호스트 디렉토리와 파일들을 겹쳐서 마운트하는 유형의 공격을 피하기 위한 것이다. (절대 경로로 된 마운트 소스 내에 존재하는 심볼릭 링크들은 무시될 것이다.)
+        하지만, 만약 컨테이너 설정에서 컨테이너 사용자가 제어할 수 있는, 예를 들어 /home/joe와 같은 디렉토리를 컨테이너 내의 <filename>path</filename>에 먼저 마운트 하고 나서,  <filename>path</filename> 내에 또 마운트를 하는 경우가 있다면,
+        컨테이너 사용자가 자신의 home 디렉토리에 있는 심볼릭링크를 정확한 시간에 조작하여, TOCTTOU (역주 : Time of check to time of use) 공격이 가능할 것이다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.mount</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify a file location in
+             the <filename>fstab</filename> format, containing the
+             mount information.  The mount target location can and in
+             most cases should be a relative path, which will become
+             relative to the mounted container root.  For instance,
+              -->
+              마운트 정보를 담은 <filename>fstab</filename> 형식으로 된 파일의 위치를 지정한다.
+              이 마운트 대상 위치들은 대부분 상대경로로 되어 있으며, 이는 마운트된 컨테이너 루트에서의 상대경로를 의미한다.
+            </para>
+<screen>
+proc proc proc nodev,noexec,nosuid 0 0
+</screen>
+            <para>
+               <!--
+             Will mount a proc filesystem under the container's /proc,
+             regardless of where the root filesystem comes from.  This
+             is resilient to block device backed filesystems as well as
+             container cloning.
+              -->
+               위의 예는 proc 파일시스템을 컨테이너 루트 파일시스템의 위치와 상관없이 컨테이너의 /proc에 마운트시키는 예제이다. 이는 백엔드 파일시스템 블록 장치뿐만 아니라 컨테이너의 복제에도 유연하게 대처할 수 있다.
+            </para>
+            <para>
+              <!--
+             Note that when mounting a filesystem from an
+             image file or block device the third field (fs_vfstype)
+             cannot be auto as with
+              <citerefentry>
+               <refentrytitle>mount</refentrytitle>
+                <manvolnum>8</manvolnum>
+              </citerefentry>
+              but must be explicitly specified.
+              -->
+              이미지 파일이나 블록 장치에서 마운트된 파일시스템의 경우, 3번째 필드 (fs_vfstype)는
+              <citerefentry>
+               <refentrytitle>mount</refentrytitle>
+                <manvolnum>8</manvolnum>
+              </citerefentry>
+              와 같이 auto를 지정할수 없으며, 명시적으로 지정해야 한다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.mount.entry</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify a mount point corresponding to a line in the
+             fstab format.
+              -->
+              fstab의 형식으로, 한 줄당 마운트 포인트 하나를 지정한다.
+
+              <!--
+             Moreover lxc add two options to mount.
+              <option>optional</option> don't fail if mount does not work.
+              <option>create=dir</option> or <option>create=file</option>
+              to create dir (or file) when the point will be mounted.
+              -->
+              또한 마운트 옵션에 아래 2가지 옵션을 추가적으로 사용할 수 있다. 이는 LXC 자체적으로 사용하는 옵션이다.
+              <option>optional</option>은 마운트를 못하더라도, 실패로 처리하지 않게 한다.
+              <option>create=dir</option>와 <option>create=file</option>는 마운트할 때, 디렉토리(dir) 또는 파일(file)을 생성한다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.mount.auto</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify which standard kernel file systems should be
+             automatically mounted. This may dramatically simplify
+             the configuration. The file systems are:
+              -->
+              일반적인 커널의 파일시스템을 자동으로 마운트할지 지정한다.
+              이 옵션을 사용하면 설정을 매우 편하게 할 수 있다.
+              사용할 수 있는 파일시스템들은 아래와 같다.
+           </para>
+           <itemizedlist>
+             <listitem>
+                <!--
+               <para>
+                 <option>proc:mixed</option> (or <option>proc</option>):
+                 mount <filename>/proc</filename> as read-write, but
+                 remount <filename>/proc/sys</filename> and
+                 <filename>/proc/sysrq-trigger</filename> read-only
+                 for security / container isolation purposes.
+               </para>
+                -->
+                <para>
+                  <option>proc:mixed</option> (or <option>proc</option>):
+                  <filename>/proc</filename> 을 읽기/쓰기 가능으로 마운트, 그러나 <filename>/proc/sys</filename>과 <filename>/proc/sysrq-trigger</filename>는 읽기 전용으로 다시 마운트 (보안상의 이유 및 컨테이너 고립을 위해)
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>proc:rw</option>: mount
+                 <filename>/proc</filename> as read-write
+               </para>
+                -->
+                <para>
+                 <option>proc:rw</option>:
+                  <filename>/proc</filename> 전체를 읽기/쓰기 가능으로 마운트
+                </para>
+             </listitem>
+             <listitem>
+               <!--
+                <para>
+                  <option>sys:mixed</option> (or <option>sys</option>):
+                  mount <filename>/sys</filename> as read-only but with
+                  /sys/devices/virtual/net writable.
+                </para>
+               -->
+               <para>
+                 <option>sys:mixed</option> (or <option>sys</option>):
+                 /sys/devices/virtual/net는 쓰기 가능으로,  <filename>/sys</filename>는 읽기 전용으로 마운트.
+               </para>
+              </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>sys:ro</option>
+                 mount <filename>/sys</filename> as read-only
+                 for security / container isolation purposes.
+               </para>
+                -->
+                <para>
+                  <option>sys:ro</option>:
+                  <filename>/sys</filename>를 읽기 전용으로 마운트 (보안상의 이유 및 컨테이너 고립을 위해)
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>sys:rw</option>: mount
+                 <filename>/sys</filename> as read-write
+               </para>
+                -->
+                <para>
+                 <option>sys:rw</option>:
+                  <filename>/sys</filename>를 읽기/쓰기 가능으로 마운트
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup:mixed</option>:
+                 mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
+                 create directories for all hierarchies to which
+                 the container is added, create subdirectories
+                 there with the name of the cgroup, and bind-mount
+                 the container's own cgroup into that directory.
+                 The container will be able to write to its own
+                 cgroup directory, but not the parents, since they
+                 will be remounted read-only.
+               </para>
+                -->
+                <para>
+                 <option>cgroup:mixed</option>:
+                  <filename>/sys/fs/cgroup</filename>를 tmpfs로 마운트.
+                  컨테이너가 추가될 모든 계층의 디렉토리 생성.
+                  cgroup 이름의 하위 디렉토리 생성.
+                  컨테이너 자신의 cgroup을 해당 디렉토리에 마운트.
+                  컨테이너는 자신의 cgroup 디렉토리에는 쓰기가 가능하지만 부모의 디렉토리는 읽기전용으로 마운트 하므로 쓰기가 불가능하다.
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup:ro</option>: similar to
+                 <option>cgroup:mixed</option>, but everything will
+               be mounted read-only.
+               </para>
+                -->
+                <para>
+                 <option>cgroup:ro</option>:
+                  <option>cgroup:mixed</option>와 유사, 단, 전부 읽기 전용으로 마운트
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup:rw</option>: similar to
+                 <option>cgroup:mixed</option>, but everything will
+                 be mounted read-write. Note that the paths leading
+                 up to the container's own cgroup will be writable,
+                 but will not be a cgroup filesystem but just part
+                 of the tmpfs of <filename>/sys/fs/cgroup</filename>
+               </para>
+                -->
+                <para>
+                 <option>cgroup:rw</option>:
+                  <option>cgroup:mixed</option>와 유사, 단, 전부 읽기/쓰기 가능으로 마운트.
+                  컨테이너 자신의 cgroup에 이르기까지의 경로가 모두 쓰기 가능이 되지만, cgroup 파일시스템이 아닌 <filename>/sys/fs/cgroup</filename>의 tmpfs의 일부로써 존재하게 되는 것에 주의해야 한다.
+                </para>
+             </listitem>
+             <listitem>
+               <para>
+                  <!--
+                 <option>cgroup</option> (without specifier):
+                 defaults to <option>cgroup:rw</option> if the
+                 container retains the CAP_SYS_ADMIN capability,
+                 <option>cgroup:mixed</option> otherwise.
+                  -->
+                 <option>cgroup</option> (별다른 옵션 없이):
+                  컨테이너가 CAP_SYS_ADMIN capability를 유지하고 있는 경우 <option>cgroup:rw</option>을 기본으로 사용한다. 그렇지 않다면 <option>cgroup:mixed</option>를 사용한다.
+               </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup-full:mixed</option>:
+                 mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
+                 create directories for all hierarchies to which
+                 the container is added, bind-mount the hierarchies
+                 from the host to the container and make everything
+                 read-only except the container's own cgroup. Note
+                 that compared to <option>cgroup</option>, where
+                 all paths leading up to the container's own cgroup
+                 are just simple directories in the underlying
+                 tmpfs, here
+                 <filename>/sys/fs/cgroup/$hierarchy</filename>
+                 will contain the host's full cgroup hierarchy,
+                 albeit read-only outside the container's own cgroup.
+                 This may leak quite a bit of information into the
+                 container.
+               </para>
+                -->
+                <para>
+                 <option>cgroup-full:mixed</option>:
+                  <filename>/sys/fs/cgroup</filename>을 tmpfs로 마운트.
+                  컨테이너가 추가될 모든 계층의 디렉토리 생성.
+                  호스트의 디렉토리들을 컨테이너로 바인드 마운트하고 컨테이너 자신의 cgroup을 제외한 모든 디렉토리는 읽기 전용으로 변경.
+                  비교하자면, <option>cgroup</option>의 경우에는 컨테이너 자신의 cgroup에 이르기까지 모든 경로는 단순하게 tmpfs 아래에 있는 디렉토리에 불과하다. 하지만, 여기서는 비록 컨테이너 자신의 cgroup 이외에는 모두 읽기 전용이긴 하나 <filename>/sys/fs/cgroup/$hierarchy</filename>이 호스트의 모든 cgroup 계층구조를 포함하고 있다.
+                  이는 컨테이너에게 너무 많은 정보를 노출시킬 수 있다.
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup-full:ro</option>: similar to
+                 <option>cgroup-full:mixed</option>, but everything
+                 will be mounted read-only.
+               </para>
+                -->
+                <para>
+                 <option>cgroup-full:ro</option>:
+                  <option>cgroup-full:mixed</option>와 유사, 단, 전부 읽기 전용으로 마운트
+                </para>
+             </listitem>
+             <listitem>
+                <!--
+               <para>
+                 <option>cgroup-full:rw</option>: similar to
+                 <option>cgroup-full:mixed</option>, but everything
+                 will be mounted read-write. Note that in this case,
+                 the container may escape its own cgroup. (Note also
+                 that if the container has CAP_SYS_ADMIN support
+                 and can mount the cgroup filesystem itself, it may
+                 do so anyway.)
+               </para>
+                -->
+                <para>
+                 <option>cgroup-full:rw</option>:
+                 <option>cgroup-full:mixed</option>와 유사, 단, 전부 읽기/쓰기 가능으로 마운트.
+                  이 경우는 컨테이너가 자기자신의 cgroup을 벗어날 수 있다. (만약 컨테이너가 CAP_SYS_ADMIN을 갖고 있다면, cgroup 파일시스템 자체를 마운트할 수 있음을 주의해야 한다. 이렇게 하면 같은 결과를 가져올 수 있다)
+                </para>
+             </listitem>
+             <listitem>
+               <para>
+                  <!--
+                 <option>cgroup-full</option> (without specifier):
+                 defaults to <option>cgroup-full:rw</option> if the
+                 container retains the CAP_SYS_ADMIN capability,
+                 <option>cgroup-full:mixed</option> otherwise.
+                  -->
+                 <option>cgroup-full</option> (별다른 옵션 없이):
+                  컨테이너가 CAP_SYS_ADMIN capability를 유지하고 있는 경우 <option>cgroup-full:rw</option>을 기본으로 사용한다. 그렇지 않다면 <option>cgroup-full:mixed</option>를 사용한다.
+               </para>
+             </listitem>
+           </itemizedlist>
+            <para>
+              <!--
+              If cgroup namespaces are enabled, then any <option>cgroup</option>
+              auto-mounting request will be ignored, since the container can
+              mount the filesystems itself, and automounting can confuse the
+              container init.
+              -->
+              cgroup 네임스페이스가 사용 가능한 경우, <option>cgroup</option> 마운트 옵션들은 전부 무시될 것이다. 컨테이너가 직접 파일시스템을 마운트하기 때문이며, 컨테이너 초기화시 해당 옵션이 혼란을 줄 수 있기 때문이다.
+            </para>
+           <para>
+              <!--
+             Note that if automatic mounting of the cgroup filesystem
+             is enabled, the tmpfs under
+             <filename>/sys/fs/cgroup</filename> will always be
+             mounted read-write (but for the <option>:mixed</option>
+             and <option>:ro</option> cases, the individual
+             hierarchies,
+             <filename>/sys/fs/cgroup/$hierarchy</filename>, will be
+             read-only). This is in order to work around a quirk in
+             Ubuntu's
+              <citerefentry>
+               <refentrytitle>mountall</refentrytitle>
+                <manvolnum>8</manvolnum>
+              </citerefentry>
+             command that will cause containers to wait for user
+             input at boot if
+             <filename>/sys/fs/cgroup</filename> is mounted read-only
+             and the container can't remount it read-write due to a
+             lack of CAP_SYS_ADMIN.
+              -->
+              cgroup 파일시스템이 자동으로 마운트되는게 활성화되어 있다면, <filename>/sys/fs/cgroup</filename> 밑의 tmpfs는 언제나 읽기/쓰기 가능으로 마운트 된다.(단, <option>:mixed</option>과 <option>:ro</option>의 경우에는 각각 계층 <filename>/sys/fs/cgroup/$hierarchy</filename>이 읽기전용이 될 수는 있다)
+              아래의  Ubuntu 명령어에 대응하기 위함이다.
+              <citerefentry>
+               <refentrytitle>mountall</refentrytitle>
+                <manvolnum>8</manvolnum>
+              </citerefentry>
+              해당 명령어는 컨테이너 부팅시에 <filename>/sys/fs/cgroup</filename>가 읽기전용으로 마운트되어 있고, 컨테이너가 CAP_SYS_ADMIN을 갖고 있지 않아 이를 읽기/쓰기 전용으로 다시 마운트 못할 경우, 부팅시에 사용자의 입력을 기다리게 만들기 때문이다.
+           </para>
+           <para>
+              <!--
+             Examples:
+              -->
+              예제:
+           </para>
+           <programlisting>
+             lxc.mount.auto = proc sys cgroup
+             lxc.mount.auto = proc:rw sys:rw cgroup-full:rw
+           </programlisting>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Root file system -->루트 파일시스템</title>
+      <para>
+        <!--
+       The root file system of the container can be different than that
+       of the host system.
+        -->
+        컨테이너의 루트 파일시스템은 호스트 시스템과 다르게 구성할 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.rootfs</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the root file system for the container. It can
+             be an image file, a directory or a block device. If not
+             specified, the container shares its root file system
+             with the host.
+              -->
+              컨테이너의 루트 파일시스템을 지정한다. 이미지 파일 또는 블록 장치의 디렉토리가 될 수도 있다. 만약 지정되지 않으면 컨테이너는 자신의 루트 파일시스템을 호스트와 공유한다.
+           </para>
+           <para>
+              <!--
+          For directory or simple block-device backed containers,
+          a pathname can be used.  If the rootfs is backed by a nbd
+          device, then <filename>nbd:file:1</filename> specifies that
+          <filename>file</filename> should be attached to a nbd device,
+          and partition 1 should be mounted as the rootfs.
+          <filename>nbd:file</filename> specifies that the nbd device
+          itself should be mounted.  <filename>overlayfs:/lower:/upper</filename>
+          specifies that the rootfs should be an overlay with <filename>/upper</filename>
+          being mounted read-write over a read-only mount of <filename>/lower</filename>.
+          <filename>aufs:/lower:/upper</filename> does the same using aufs in place
+          of overlayfs. For both <filename>overlayfs</filename> and
+          <filename>aufs</filename> multiple <filename>/lower</filename>
+          directories can be specified. <filename>loop:/file</filename> tells lxc to attach
+          <filename>/file</filename> to a loop device and mount the loop device.
+          -->
+              디렉토리 또는 간단한 블록 장치로 구성된 컨테이너를 위해서 경로이름이 사용될 수 있다. 만약 루트 파일시스템이 nbd 장치의 경우, <filename>nbd:file:1</filename>는 <filename>file</filename>을 nbd 장치로 사용하고 1번 파티션이 루트 파일시스템으로 마운트되도록 지정한다.
+              <filename>nbd:file</filename>는 nbd 장치 자체가 마운트되어야 한다고 지정한다.
+              <filename>overlayfs:/lower:/upper</filename>는 루트 파일시스템이 읽기전용으로 마운트된 <filename>/lower</filename>를 <filename>/upper</filename>가 읽기/쓰기 가능으로 오버레이 마운트되도록 지정한다.
+              <filename>aufs:/lower:/upper</filename>는 aufs에서 위와같이 지정한다. <filename>overlayfs</filename>와 <filename>aufs</filename>는 여러개의 <filename>/lower</filename> 디렉토리를 지정할 수 있다.
+              <filename>loop:/file</filename>는 lxc가 <filename>/file</filename>을 loop 장치로 사용하고 loop 장치를 마운트하도록 지정한다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.rootfs.mount</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             where to recursively bind <option>lxc.rootfs</option>
+             before pivoting.  This is to ensure success of the
+             <citerefentry>
+               <refentrytitle><command>pivot_root</command></refentrytitle>
+               <manvolnum>8</manvolnum>
+             </citerefentry>
+             syscall.  Any directory suffices, the default should
+             generally work.
+              -->
+              루트 파일시스템을 변경하기 전에, <option>lxc.rootfs</option>을 어디에 재귀적으로 바인드할지 정한다. 이는 
+             <citerefentry>
+               <refentrytitle><command>pivot_root</command></refentrytitle>
+               <manvolnum>8</manvolnum>
+             </citerefentry> 
+              시스템 콜의 성공을 보장한다.
+              어떤 디렉토리도 좋으며, 기본값으로도 보통 동작할 것이다.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
+           <option>lxc.rootfs.options</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             extra mount options to use when mounting the rootfs.
+              -->
+              루트 파일시스템을 마운트 할때 사용할 부가적인 마운트 옵션.
+           </para>
+         </listitem>
+       </varlistentry>
+
+        <varlistentry>
+          <term>
+            <option>lxc.rootfs.backend</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              specify the rootfs backend type to use, for instance 'dir' or
+              'zfs'.  While this can be guessed by lxc at container startup,
+              doing so takes time.  Specifying it here avoids extra
+              processing.
+              -->
+              사용하고자 하는 백엔드 루트파일 시스템의 종류를 지정한다. 'dir' 또는 'zfs'로 지정할 수 있다. 컨테이너 시작시 어떤 종류인지 추정하는 동안, 시간이 소요될 수 있다. 이 값을 지정함으로써 추가적인 처리를 피할 수 있다.
+            </para>
+          </listitem>
+        </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Control group -->컨트롤 그룹</title>
+      <para>
+        <!--
+       The control group section contains the configuration for the
+       different subsystem. <command>lxc</command> does not check the
+       correctness of the subsystem name. This has the disadvantage
+       of not detecting configuration errors until the container is
+       started, but has the advantage of permitting any future
+       subsystem.
+        -->
+        컨트롤 그룹 섹션은 (lxc와는) 다른 서브시스템의 설정을 포함한다.
+        <command>lxc</command>는 서브시스템의 이름을 정확히 체크하지 않는다.
+        이는 컨테이너를 시작할 때까지는 설정 상의 에러를 잡아내기 힘들게 한다.
+        그러나 다른 차후에 들어올 수 있는 서브시스템을 지원할 수 있는 장점도 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.cgroup.[subsystem name]</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             specify the control group value to be set.  The
+             subsystem name is the literal name of the control group
+             subsystem.  The permitted names and the syntax of their
+             values is not dictated by LXC, instead it depends on the
+             features of the Linux kernel running at the time the
+             container is started,
+             eg. <option>lxc.cgroup.cpuset.cpus</option>
+              -->
+              지정한 컨트롤 그룹의 값을 지정한다.
+              서브시스템의 이름은 컨트롤 그룹에서의 이름이다.
+              사용가능한 이름이나 값의 문법에 대해서는 LXC에서 따로 신경쓰지 않으며, 컨테이너가 시작하는 시점에 리눅스 커널이 해당 기능을 지원하는지에 달려있다.
+              예를 들면 <option>lxc.cgroup.cpuset.cpus</option>이다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Capabilities</title>
+      <para>
+        <!--
+       The capabilities can be dropped in the container if this one
+       is run as root.
+        -->
+        컨테이너가 root로 실행된다면, 컨테이너 내에서 capability를 제거할 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.cap.drop</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the capability to be dropped in the container. A
+             single line defining several capabilities with a space
+             separation is allowed. The format is the lower case of
+             the capability definition without the "CAP_" prefix,
+             eg. CAP_SYS_MODULE should be specified as
+             sys_module. See
+             <citerefentry>
+               <refentrytitle><command>capabilities</command></refentrytitle>
+               <manvolnum>7</manvolnum>
+              </citerefentry>.
+              If used with no value, lxc will clear any drop capabilities
+              specified up to this point.
+              -->
+              컨테이너에서 제거할 capability를 지정한다.
+              한 줄에 여러개의 capability를 공백(space)으로 구분하여 정의할 수 있다.
+              형식은 capability 정의에서 "CAP_" 접두사를 빼고 소문자로 작성하는 것이다. 예를들어 CAP_SYS_MODULE의 경우는 sys_module이다.
+              아래를 참조할 수 있다.
+             <citerefentry>
+               <refentrytitle><command>capabilities</command></refentrytitle>
+               <manvolnum>7</manvolnum>
+             </citerefentry>
+               값을 공백으로 지정하면, 해당 설정 이전에 지정했던 capability를 모두 취소한다. (lxc.cap.drop에 아무 것도 지정하지 않은 상태가 된다.)
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <option>lxc.cap.keep</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the capability to be kept in the container. All other
+             capabilities will be dropped. When a special value of "none" is
+             encountered, lxc will clear any keep capabilities specified up
+             to this point. A value of "none" alone can be used to drop all
+             capabilities.
+              -->
+              컨테이너에서 유지할 capability를 지정한다.
+              다른 capability는 모두 제거될 것이다. "none"이라는 값을 지정하면, lxc는 해당 시점에서 갖고 있던 모든 capability를 제거한다.
+              모든 capability를 제거하기 위해서는 "none" 하나만 사용하면 된다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Apparmor profile -->Apparmor 프로파일</title>
+      <para>
+        <!--
+       If lxc was compiled and installed with apparmor support, and the host
+       system has apparmor enabled, then the apparmor profile under which the
+       container should be run can be specified in the container
+        configuration.  The default is <command>lxc-container-default-cgns</command>
+       if the host kernel is cgroup namespace aware, or
+       <command>lxc-container-default</command> othewise.
+        -->
+        lxc가 apparmor를 지원하도록 컴파일된 후 설치되었고, 호스트 시스템에서 apparmor가 활성화되었다면, 컨테이너에서 따라야할 apparmor 프로파일을 컨테이너 설정에서 지정할 수 있다. 기본값은 호스트 커널이 cgroup 네임스페이스를 지원하면 <command>lxc-container-default-cgns</command>이고, 그렇지 않다면 <command>lxc-container-default</command>이다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.aa_profile</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the apparmor profile under which the container should
+             be run.  To specify that the container should be unconfined,
+             use
+              -->
+              컨테이너가 따라야할 apparmor 프로파일을 지정한다.
+              컨테이너가 apparmor로 인한 제한을 받지 않도록 하려면, 아래와 같이 지정하면 된다.
+           </para>
+             <programlisting>lxc.aa_profile = unconfined</programlisting>
+            <para>
+             <!--
+              If the apparmor profile should remain unchanged (i.e. if you
+             are nesting containers and are already confined), then use
+             -->
+              apparmor 프로파일이 변경되지 않아야 한다면(중첩 컨테이너 안에 있고, 이미 confined된 경우), 아래와 같이 지정하면 된다.
+            </para>
+              <programlisting>lxc.aa_profile = unchanged</programlisting>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <option>lxc.aa_allow_incomplete</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Apparmor profiles are pathname based.  Therefore many file
+             restrictions require mount restrictions to be effective against
+             a determined attacker.  However, these mount restrictions are not
+             yet implemented in the upstream kernel.  Without the mount
+             restrictions, the apparmor profiles still protect against accidental
+             damager.
+              -->
+              apparmor 프로파일은 경로이름 기반이므로, 공격자로부터 효과적으로 파일 제한을 하기위해서는 마운트 제한이 요구된다.
+              하지만 이 마운트 제한들은 upstream 커널에서는 구현되어 있지 않다.
+              마운트 제한 없이도, apparmor 프로파일은 우연한 손상에 대해서 보호가 가능하다.
+           </para>
+           <para>
+              <!--
+             If this flag is 0 (default), then the container will not be
+             started if the kernel lacks the apparmor mount features, so that a
+             regression after a kernel upgrade will be detected.  To start the
+             container under partial apparmor protection, set this flag to 1.
+              -->
+              만약 이 플래그가 0(기본값)이라면, 커널에 apparmor의 마운트 기능이 부족했을때 컨테이너가 시작되지 않는다. 커널을 업그레이드한 후에 해당 기능이 빠졌는지 여부를 검사하기 위함이다. 부분적인 apparmor 보호 하에서도 컨테이너를 시작하려면, 플래그를 1로 지정하면 된다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- SELinux context -->SELinux 컨텍스트</title>
+      <para>
+        <!--
+       If lxc was compiled and installed with SELinux support, and the host
+       system has SELinux enabled, then the SELinux context under which the
+       container should be run can be specified in the container
+       configuration.  The default is <command>unconfined_t</command>,
+       which means that lxc will not attempt to change contexts.
+       See @DATADIR@/lxc/selinux/lxc.te for an example policy and more
+       information.
+        -->
+        lxc가 SELinux를 지원하도록 컴파일된 후 설치되었고, 호스트 시스템에서 SELinux 컨텍스트가 활성화되었다면, 컨테이너에서 따라야할 SELinux 컨텍스트를 컨테이너 설정에서 지정할 수 있다.
+        기본값은 <command>unconfined_t</command>이다. 이는 lxc는 컨텍스트를 변경하지않음을 의미한다.
+        정책 예제와 추가적인 정보를 원한다면 @DATADIR@/lxc/selinux/lxc.te를 참고하면 된다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.se_context</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify the SELinux context under which the container should
+             be run or <command>unconfined_t</command>. For example
+              -->
+              컨테이너가 따라야할 SELinux 컨텍스트를 지정하거나, <command>unconfined_t</command>를 지정할 수 있다. 예를 들어 아래와 같이 지정 가능하다.
+           </para>
+           <programlisting>lxc.se_context = system_u:system_r:lxc_t:s0:c22</programlisting>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Seccomp configuration -->Seccomp 설정</title>
+      <para>
+        <!--
+        A container can be started with a reduced set of available
+       system calls by loading a seccomp profile at startup.  The
+       seccomp configuration file must begin with a version number
+       on the first line, a policy type on the second line, followed
+       by the configuration.
+        -->
+        컨테이너는 seccomp 프로파일을 로드하여 사용가능한 시스템콜의 수를 줄인 체로 실행할 수 있다.
+        seccomp 설정파일은 첫번째 행이 버전번호, 두번째 행이 정책 타입, 시작하며 그 이후에 설정 사항들이 포함되어야 한다.
+      </para>
+      <para>
+        <!--
+        Versions 1 and 2 are currently supported.  In version 1, the
+       policy is a simple whitelist.  The second line therefore must
+       read "whitelist", with the rest of the file containing one (numeric)
+       sycall number per line.  Each syscall number is whitelisted,
+       while every unlisted number is blacklisted for use in the container
+        -->
+        현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "whitelist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다.
+      </para>
+
+      <para>
+        <!--
+       In version 2, the policy may be blacklist or whitelist,
+       supports per-rule and per-policy default actions, and supports
+       per-architecture system call resolution from textual names.
+          -->
+        버전 2에서는 폴리시는 블랙리스트 또는 화이트리스트가 될 수 있다. 그리고  각 규칙와 각 정책의 기본 동작, 아키텍쳐별 시스템콜 설정, 텍스트로된 이름을 지원한다.
+      </para>
+      <para>
+        <!--
+       An example blacklist policy, in which all system calls are
+       allowed except for mknod, which will simply do nothing and
+       return 0 (success), looks like:
+       -->
+        아래는 블랙리스트 정책 예제이다. 아래 정책에서는 mknod를 제외한 모든 시스템콜이 허용된다. mknod시에는 아무것도 수행하지 않고 0(성공)을 반환한다.
+      </para>
+<screen>
+2
+blacklist
+mknod errno 0
+</screen>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.seccomp</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify a file containing the seccomp configuration to
+             load before the container starts.
+              -->
+              컨테이너가 시작되기전에 읽어올 seccomp 설정이 담긴 파일을 지정한다.
+            </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- UID mappings -->UID 매핑</title>
+      <para>
+        <!--
+        A container can be started in a private user namespace with
+       user and group id mappings.  For instance, you can map userid
+       0 in the container to userid 200000 on the host.  The root
+       user in the container will be privileged in the container,
+       but unprivileged on the host.  Normally a system container
+       will want a range of ids, so you would map, for instance,
+       user and group ids 0 through 20,000 in the container to the
+       ids 200,000 through 220,000.
+        -->
+        컨테이너는 사용자와 그룹 ID 매핑을 통해 자신만의 사용자 네임스페이스 내에서 실행될수 있다.
+        예를 들어서 컨테이너의 UID 0번을 호스트의 UID 200000으로 매핑할 수 있다.        컨테이너의 루트 사용자는 컨테이너에서는 특권을 가지고 있지만, 호스트에서는 특권을 가지고 있지 않게 된다.
+        보통 시스템 컨테이너는 ID들의 범위를 지정하려 할텐데 그 역시도 지정 가능하다. 예를 들어서, 컨테이너의 UID와 GID를 0 ~ 20,000를 호스트의 200,000 ~ 220,000로 설정 가능하다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.id_map</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Four values must be provided.  First a character, either
+             'u', or 'g', to specify whether user or group ids are
+             being mapped.  Next is the first userid as seen in the
+             user namespace of the container.  Next is the userid as
+             seen on the host.  Finally, a range indicating the number
+             of consecutive ids to map.
+              -->
+              4개의 값이 제공되어야 한다. 첫 번째는 'u', 'g', 'b' 문자로 각각 UID, GID, 또는 UID 및 GID 를 가리킨다. 그 다음은 사용자 네임스페이스내에서의 UID, 그다음은 호스트의 UID, 그리고 마지막으로 매핑할 ID의 범위를 지정한다.
+            </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Container hooks -->컨테이너 훅</title>
+      <para>
+        <!--
+        Container hooks are programs or scripts which can be executed
+       at various times in a container's lifetime.
+        -->
+        컨테이너 훅은 컨테이너의 생명주기 내에서 다양한 상황에 실행되는 프로그램 또는 스크립트이다.
+      </para>
+      <para>
+        <!--
+        When a container hook is executed, information is passed both
+       as command line arguments and through environment variables.
+       The arguments are:
+       <itemizedlist>
+         <listitem><para> Container name. </para></listitem>
+         <listitem><para> Section (always 'lxc'). </para></listitem>
+         <listitem><para> The hook type (i.e. 'clone' or 'pre-mount'). </para></listitem>
+         <listitem><para> Additional arguments. In the
+         case of the clone hook, any extra arguments passed to
+         lxc-clone will appear as further arguments to the hook.
+         In the case of the stop hook, paths to filedescriptors
+         for each of the container's namespaces along with their types
+         are passed. </para></listitem>
+       </itemizedlist>
+       The following environment variables are set:
+       <itemizedlist>
+         <listitem><para> LXC_NAME: is the container's name. </para></listitem>
+         <listitem><para> LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. </para></listitem>
+         <listitem><para> LXC_CONFIG_FILE: the path to the container configuration file. </para></listitem>
+         <listitem><para> LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. </para></listitem>
+         <listitem><para> LXC_ROOTFS_PATH: this is the lxc.rootfs entry for the container.  Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. </para></listitem>
+       </itemizedlist>
+        -->
+        컨테이너 훅이 실행될 때, 정보는 명령어 인수나 환경 변수를 통해 넘겨진다.
+        인수 :
+       <itemizedlist>
+         <listitem><para>컨테이너 이름</para></listitem>
+         <listitem><para>섹션 (보통 'lxc')</para></listitem>
+         <listitem><para>훅 종류 ('clone', 'pre-mount' 등)</para></listitem>
+         <listitem><para>추가 인수. clone 훅일 경우, lxc-clone에게 넘였던 추가 인수들이 넘어온다. stop 훅일 경우, 컨테이너의 네임스페이스 각각에 대한 이름과 파일 디스크립터의 경로가 넘어온다.</para></listitem>
+       </itemizedlist>
+        환경 변수 :
+       <itemizedlist>
+         <listitem><para> LXC_NAME: 컨테이너 이름</para></listitem>
+         <listitem><para> LXC_ROOTFS_MOUNT: 마운트될 루트 파일시스템의 경로</para></listitem>
+         <listitem><para> LXC_CONFIG_FILE: 컨테이너 설정파일의 경로</para></listitem>
+         <listitem><para> LXC_SRC_NAME: clone 훅의 경우, 원본 컨테이너의 이름</para></listitem>
+         <listitem><para> LXC_ROOTFS_PATH: 컨테이너의 lxc.rootfs 항목. 이 것은 마운트된 루트 파일시스템을 가리키는 것이 아님에 주의해야한다. 그 목적을 위해서는  LXC_ROOTFS_MOUNT를 사용해야 한다.</para></listitem>
+        </itemizedlist>
+      </para>
+      <para>
+        <!--
+        Standard output from the hooks is logged at debug level.
+        Standard error is not logged, but can be captured by the
+        hook redirecting its standard error to standard output.
+        -->
+        훅의 표준출력은 debug 수준 로그로 납겨진다.
+        표준 에러는 로그로 남겨지지는 않지만, 표준 에러를 표준 출력으로 리
+다이렉션하여 로그로 남길 수 있다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.pre-start</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the host's namespace before the
+             container ttys, consoles, or mounts are up.
+              -->
+              컨테이너의 tty, 콘솔의 생성 및 마운트가 되기 전에, 호스트의 네임스페이스에서 실행되는 훅.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.pre-mount</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the container's fs namespace but before
+             the rootfs has been set up.  This allows for manipulation
+             of the rootfs, i.e. to mount an encrypted filesystem.  Mounts
+             done in this hook will not be reflected on the host (apart from
+             mounts propagation), so they will be automatically cleaned up
+             when the container shuts down.
+              -->
+              컨테이너의 마운트 네임스페이스 안에서 루트 파일시스템이 세팅되기 전에 실행되는 훅.
+              예를 들어 암호화 파일시스템을 마운트 하는 등의 루트 파일시스템을 조작할 수 있게 해준다. 이 훅에서 마운트를 하더라도 호스트에는 반영되지 않는다. (mounts propagation은 제외) 그래서 컨테이너가 종료되면 자동적으로 정리된다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.mount</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the container's namespace after
+             mounting has been done, but before the pivot_root.
+              -->
+              마운트가 완료된 후 pivot_root 전에, 컨테이너의 마운트 네임스페이스에서 실행되는 훅.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.autodev</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the container's namespace after
+             mounting has been done and after any mount hooks have
+             run, but before the pivot_root, if
+             <option>lxc.autodev</option> == 1.
+             The purpose of this hook is to assist in populating the
+             /dev directory of the container when using the autodev
+             option for systemd based containers.  The container's /dev
+             directory is relative to the
+             ${<option>LXC_ROOTFS_MOUNT</option>} environment
+             variable available when the hook is run.
+              -->
+              <option>lxc.autodev</option> == 1가 지정되어 있는 경우에 마운트 완료시 마운트 훅도 실행 된 후 pivot_root전에, 컨테이너의 마운트 네임스페이스에서 실행되는 훅.
+              이 훅의 목적은 systemd 기반의 컨테이너에서 autodev 옵션을 사용하는 경우  /dev 디렉토리를 구성할 때 도움을 주기위한 것이다.
+              훅이 실행될 때, 컨테이너의 /dev 경로는 ${<option>LXC_ROOTFS_MOUNT</option>} 환경변수에 대한 경로이다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.start</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the container's namespace immediately
+             before executing the container's init.  This requires the
+             program to be available in the container.
+              -->
+              컨테이너의 init이 실행되기 직전에 컨테이너의 네임스페이스에서 실행되는 훅. 컨테이너 내에서 해당 프로그램이 실행될 수 있는 상태여야 한다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.stop</option>
+         </term>
+         <listitem>
+           <para>
+             <!--
+             A hook to be run in the host's namespace with references
+             to the container's namespaces after the container has been shut
+             down. For each namespace an extra argument is passed to the hook
+             containing the namespace's type and a filename that can be used to
+             obtain a file descriptor to the corresponding namespace, separated
+             by a colon. The type is the name as it would appear in the
+             <filename>/proc/PID/ns</filename> directory.
+             For instance for the mount namespace the argument usually looks
+             like <filename>mnt:/proc/PID/fd/12</filename>.
+             -->
+             컨테이너가 종료된 후 컨테이너 네임스페이스에 대한 참조를 넘겨받는 호스트의 네임스페이스에서 실행되는 훅.
+             각각의 네임스페이스들은 훅에 추가인수로 넘겨진다. 해당 인수는 네임스페이스의 이름과 네임스페이스의 파일 디스크립터를 얻어올 수 있는 파일이름을 가지고 있으며, 콜론으로 구분된다.
+             네임스페이스 이름은 <filename>/proc/PID/ns</filename> 디렉토리 내의 파일 이름이다. 예를 들어 마운트 네임스페이스에 대응하는 인수는 일반적으로 <filename>mnt:/proc/PID/fd/12</filename>와 같이 된다.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.post-stop</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run in the host's namespace after the
+             container has been shut down.
+              -->
+              컨테이너가 종료된 후 호스트의 네임스페이스에서 실행되는 훅.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.clone</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             A hook to be run when the container is cloned to a new one.
+             See <citerefentry><refentrytitle><command>lxc-clone</command></refentrytitle>
+             <manvolnum>1</manvolnum></citerefentry> for more information.
+              -->
+              컨테이너가 새로운 컨테이너로 복제되었을 경우 실행되는 훅. 아래를 참조하면 더 자세한 정보를 얻을 수 있다.
+              <citerefentry><refentrytitle><command>lxc-clone</command></refentrytitle>
+              <manvolnum>1</manvolnum></citerefentry>
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.hook.destroy</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+              A hook to be run when the container is destroyed.
+              -->
+              컨테이너가 제거될 때 실행되는 훅.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Container hooks Environment Variables -->컨테이너 훅 환경 변수</title>
+      <para>
+        <!--
+        A number of environment variables are made available to the startup
+        hooks to provide configuration information and assist in the
+        functioning of the hooks.  Not all variables are valid in all
+        contexts.  In particular, all paths are relative to the host system
+        and, as such, not valid during the <option>lxc.hook.start</option> hook.
+        -->
+        훅이 시작될때 설정 정보를 제공하고 훅의 기능을 돕기 위해 몇가지 환경 변수가 사용 가능하다.
+        모든 컨텍스트에서 모든 변수가 사용 가능하진 않다. 특히, 모든 경로는 호스트 시스템에서의 경로이며, <option>lxc.hook.start</option> 훅에서는 유효하지 않다.
+      </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_NAME</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             The LXC name of the container.  Useful for logging messages
+             in common log environments.  [<option>-n</option>]
+              -->
+              LXC 컨테이너의 이름. 일반적인 로그 환경에서 로그메시지에 유용하게 사용할 수 있다. [<option>-n</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_CONFIG_FILE</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Host relative path to the container configuration file.  This
+             gives the container to reference the original, top level,
+             configuration file for the container in order to locate any
+             additional configuration information not otherwise made
+             available.  [<option>-f</option>]
+              -->
+              컨테이너 설정파일의 호스트에서의 경로.
+              이것은 다른 방법으로는 얻을 수 없는 추가적인 정보룰 찾을 수 있도록, 컨테이너가 참조하는 원래의 최상위 설정파일의 경로를 제공한다. [<option>-f</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_CONSOLE</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             The path to the console output of the container if not NULL.
+             [<option>-c</option>] [<option>lxc.console</option>]
+              -->
+              NULL이 아니라면, 컨테이너의 콘솔의 출력이 저장될 경로.
+             [<option>-c</option>] [<option>lxc.console</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_CONSOLE_LOGPATH</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             The path to the console log output of the container if not NULL.
+             [<option>-L</option>]
+              -->
+              NULL이 아니라면, 컨테이너의 콘솔의 로그 출력이 저장될 경로.
+             [<option>-L</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_ROOTFS_MOUNT</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             The mount location to which the container is initially bound.
+             This will be the host relative path to the container rootfs
+             for the container instance being started and is where changes
+             should be made for that instance.
+             [<option>lxc.rootfs.mount</option>]
+              -->
+              처음에 컨테이너가 마운트 되는 장소.
+              이것은 시작되는 컨테이너 인스턴스를 위한 루트 파일시스템의 호스트에서의 경로이다. 해당 인스턴스에 대한 변경이 이루어져야 하는 장소이다.
+             [<option>lxc.rootfs.mount</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>LXC_ROOTFS_PATH</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             The host relative path to the container root which has been
+             mounted to the rootfs.mount location.
+             [<option>lxc.rootfs</option>]
+              -->
+              rootfs.mount에 마운트된 컨테이너 루트의 호스트에서의 경로이다.
+              [<option>lxc.rootfs</option>]
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_SRC_NAME</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Only for the clone hook. Is set to the original container name.
+              -->
+              clone 훅에서만 사용된다. 원본 컨테이너의 이름을 지정한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_TARGET</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Only for the stop hook. Is set to "stop" for a container
+              shutdown or "reboot" for a container reboot.
+              -->
+              stop 훅에서만 사용된다. 값이 "stop"이면 컨테이너가 종료되는 것을, "reboot"이면 컨테이너가 재부팅되는 것을 의미한다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_CGNS_AWARE</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+             If unset, then this version of lxc is not aware of cgroup
+             namespaces.  If set, it will be set to 1, and lxc is aware
+             of cgroup namespaces.  Note this does not guarantee that
+             cgroup namespaces are enabled in the kernel.  This is used
+             by the lxcfs mount hook.
+             -->
+             이 변수가 지정되지 않았다면, 현재 버전의 lxc는 cgroup 네임스페이스를 지원하지 않는다. 만약 지정되었고 값이 1이라면, lxc는 cgroup 네임스페이스를 지원하는 것이다. 단, kernel에서의 cgroup 네임스페이스 지원을 보장하는 것이 아님에 주의해야 한다. lxcfs 마운트 훅에서 사용된다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+    <title><!-- Logging -->로그</title>
+    <para>
+      <!--
+      Logging can be configured on a per-container basis.  By default,
+      depending upon how the lxc package was compiled, container startup
+      is logged only at the ERROR level, and logged to a file named after
+      the container (with '.log' appended) either under the container path,
+      or under @LOGPATH@.
+      -->
+      로그는 각 컨테이너마다 설정할 수 있다.
+      기본적으로 lxc 패키지가 어떻게 컴파일되었는지에 달려있지만, 컨테이너 시작시에는 error 수준 로그만 기록된다. 컨테이너 경로나 @LOGPATH@ 밑에 컨테이너의 이름을 따서(뒤에 '.log'를 붙여서) 로그 파일을 생성한다.
+    </para>
+    <para>
+      <!--
+      Both the default log level and the log file can be specified in the
+      container configuration file, overriding the default behavior.  Note
+      that the configuration file entries can in turn be overridden by the
+      command line options to <command>lxc-start</command>.
+      -->
+      기본 로그 수준과 로그파일은 컨테이너 설정파일로 지정 가능하며, 기본 동작을 덮어버린다. 마찬가지로 설 정파일 항목들은 <command>lxc-start</command> 명령어의 옵션으로 덮어쓸 수 있다.
+    </para>
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.loglevel</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+           The level at which to log.  The log level is an integer in
+           the range of 0..8 inclusive, where a lower number means more
+           verbose debugging.  In particular 0 = trace, 1 = debug, 2 =
+           info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 =
+           alert, and 8 = fatal.  If unspecified, the level defaults
+           to 5 (error), so that only errors and above are logged.
+            -->
+              기록할 로그 수준.
+              로그 수준은 0 ~ 8 사이의 정수이다.
+              숫자가 작을수록 더 자세히 로그를 기록한다.
+              구체적으로는 0 = trace, 1 = debug, 2 = info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 = alert, 8 = fatal이다.
+              지정하지 않은 경우, 기본값은 5 (error)로, 에러 이거나 그보다 심각한 상황의 로그를 기록한다.
+           </para>
+           <para>
+              <!--
+           Note that when a script (such as either a hook script or a
+           network interface up or down script) is called, the script's
+           standard output is logged at level 1, debug.
+            -->
+            (훅 스크립트 및 네트워크 인터페이스 up/down 스크립트 같은) 스크립트가 호출이되면, 스크립트의 표준 입출력은 1 번, debug 수준으로 기록된다.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <option>lxc.logfile</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+           The file to which logging info should be written.
+            -->
+              로그 정보를 쓸 파일.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+    <title><!-- Autostart -->자동시작</title>
+    <para>
+      <!--
+        The autostart options support marking which containers should be
+        auto-started and in what order. These options may be used by LXC tools
+        directly or by external tooling provided by the distributions.
+        -->
+      자동시작 옵션들은 자동시작할 컨테이너 지정 및 순서 설정이 가능하다.
+      이 옵션들은 LXC 도구로 직접 사용하거나 배포판들이 제공하는 외부 도구에 의해 사용될 수도 있다.
+    </para>
+
+    <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.start.auto</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Whether the container should be auto-started.
+              Valid values are 0 (off) and 1 (on).
+              -->
+              컨테이너가 자동으로 시작될지 여부.
+              유효한 값은 0 (off) 또는 1 (on)이다.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.start.delay</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              How long to wait (in seconds) after the container is
+              started before starting the next one.
+              -->
+              컨테이너가 시작된 후 다음 컨테이너가 시작되기 전까지 기다릴 시간(초).
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.start.order</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              An integer used to sort the containers when auto-starting
+              a series of containers at once.
+              -->
+              다수의 컨테이너를 한번에 자동시작할 때, 컨테이너의 부팅 순서를 결정할 때 사용하는 정수를 지정한다.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.monitor.unshare</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              If not zero the mount namespace will be unshared from the host
+              before initializing the container (before running any pre-start
+              hooks). This requires the CAP_SYS_ADMIN capability at startup.
+              Default is 0.
+              -->
+              값이 0이 아니라면, 컨테이너가 초기화되기 전 (pre-start 훅이 실행 되기 전) 호스트로부터 마운트 네임스페이스를 unshare 한다. 시작시에 CAP_SYS_ADMIN 캐퍼빌리티가 요구된다. 기본값은 0이다.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.group</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              A multi-value key (can be used multiple times) to put the
+              container in a container group. Those groups can then be
+              used (amongst other things) to start a series of related
+              containers.
+              -->
+              컨테이너를 추가할 컨테이너 그룹을 지정한다. 여러값을 설정할 수 있으며, 여러번 지정 가능하다.
+              설정된 그룹은 연관된 컨테이너들을 시작할 때 사용된다.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+    <title><!-- Autostart and System Boot -->자동시작과 시스템 부팅</title>
+    <para>
+      <!--
+          Each container can be part of any number of groups or no group at all.
+          Two groups are special. One is the NULL group, i.e. the container does
+          not belong to any group. The other group is the "onboot" group.
+        -->
+          각각의 컨테이너는 여러 그룹에 속할수도 있고 아무그룹에도 속하지 않을 수 있다. 두개의 그룹은 특수한데, 하나는 NULL 그룹이고 컨테이너가 아무그룹에도 속하지 않을때 사용된다. 그리고 나머지 하나는 "onboot" 그룹이다.
+    </para>
+
+    <para>
+      <!--
+          When the system boots with the LXC service enabled, it will first
+          attempt to boot any containers with lxc.start.auto == 1 that is a member
+          of the "onboot" group. The startup will be in order of lxc.start.order.
+          If an lxc.start.delay has been specified, that delay will be honored
+          before attempting to start the next container to give the current
+          container time to begin initialization and reduce overloading the host
+          system. After starting the members of the "onboot" group, the LXC system
+          will proceed to boot containers with lxc.start.auto == 1 which are not
+          members of any group (the NULL group) and proceed as with the onboot
+          group.
+          -->
+          LXC 서비스가 활성화된 상태로 시스템이 부팅될 때, 먼저 lxc.start.auto == 1이고 "onboot" 그룹인 컨테이너들을 시작하려고 시도한다. 시작과정은 lxc.start.order의 순서대로 이루어진다.
+          만약 lxc.start.delay가 지정 되었다면, 다음 컨테이너를 시작하려고 시도>하기 전, 현재 컨테이너의 초기화 및 호스트 시스템의 부하를 줄이기 위해서 지연시간을 준다.
+          "onboot" 그룹의 멤버들을 시작시킨 후, LXC 시스템은 lxc.start.auto == 1이고 어떤 그룹에도 속하지 않은(NULL 그룹) 컨테이너들을 시작한다.
+    </para>
+
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Container Environment -->컨테이너 환경변수</title>
+      <para>
+        <!--
+       If you want to pass environment variables into the container (that
+       is, environment variables which will be available to init and all of
+       its descendents), you can use <command>lxc.environment</command>
+       parameters to do so.  Be careful that you do not pass in anything
+       sensitive; any process in the container which doesn't have its
+       environment scrubbed will have these variables available to it, and
+       environment variables are always available via
+       <command>/proc/PID/environ</command>.
+        -->
+        컨테이너에 환경변수를 념겨주고 싶다면(환경변수를 컨테이너의 init과 그 자손 전체가 사용할 수 있다), <command>lxc.environment</command>를 사용할 수 있다.
+        민감한 정보를 넘기지 않도록 주의해야 한다. 왜냐면 컨테이너의 모든 프로세스가 이 환경변수를 획득할 수 있기 때문이다. 환경변수는 항상 <command>/proc/PID/environ</command>를 통해 획득할 수 있다.
+      </para>
+
+      <para>
+        <!--
+        This configuration parameter can be specified multiple times; once
+        for each environment variable you wish to configure.
+        -->
+        이 설정항목은 여러번을 지정할 수 있으며, 설정하려는 환경변수마다 한번씩 지정한다.
+      </para>
+
+      <variablelist>
+       <varlistentry>
+         <term>
+           <option>lxc.environment</option>
+         </term>
+         <listitem>
+           <para>
+              <!--
+             Specify an environment variable to pass into the container.
+             Example:
+              -->
+              컨테이너로 전달될 환경변수를 지정한다.
+              예제:
+           </para>
+           <programlisting>
+             lxc.environment = APP_ENV=production
+             lxc.environment = SYSLOG_SERVER=192.0.2.42
+           </programlisting>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Examples -->예제</title>
+      <para>
+        <!--
+       In addition to the few examples given below, you will find
+       some other examples of configuration file in @DOCDIR@/examples
+        -->
+        아래에 소개하는 몇가지 예제말고도 다른 예제들이 @DOCDIR@/examples에 위치하고 있다.
+      </para>
+    <refsect2>
+      <title><!-- Network -->네트워크</title>
+      <para>
+        <!--
+        This configuration sets up a container to use a veth pair
+       device with one side plugged to a bridge br0 (which has been
+       configured before on the system by the administrator). The
+       virtual network device visible in the container is renamed to
+       eth0.
+        -->
+        이 설정은 컨테이너가 한 쪽은 (이전에 시스템에 이미 생성된) br0 브리지에 연결되어 있는 veth 장치 쌍을 사용하도록 세팅한다. 가상 네트워크 장치는 컨테이너 내에서 eth0라는 이름을 갖는다.
+      </para>
+      <programlisting>
+       lxc.utsname = myhostname
+       lxc.network.type = veth
+       lxc.network.flags = up
+       lxc.network.link = br0
+       lxc.network.name = eth0
+       lxc.network.hwaddr = 4a:49:43:49:79:bf
+       lxc.network.ipv4 = 1.2.3.5/24 1.2.3.255
+       lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
+      </programlisting>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- UID/GID mapping -->UID/GID 매핑</title>
+      <para><!-- This configuration will map both user and group ids in the
+        range 0-9999 in the container to the ids 100000-109999 on the host. -->
+        이 설정은 UID와 GID 둘다를 컨테이너의 0 ~ 9999를 호스트의 100000 ~ 109999로 매핑한다.
+      </para>
+      <programlisting>
+       lxc.id_map = u 0 100000 10000
+       lxc.id_map = g 0 100000 10000
+      </programlisting>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Control group -->컨트롤 그룹</title>
+      <para>
+        <!-- This configuration will setup several control groups for
+      the application, cpuset.cpus restricts usage of the defined cpu,
+      cpus.share prioritize the control group, devices.allow makes
+      usable the specified devices.-->
+        이 설정은 어플리케이션을 위해 몇가지 컨트롤 그룹을 설정한다. cpuset.cpus는 정의된 cpu만 사용하도록 제한한다. cpus.share은 컨트롤 그룹(cpu) 우선순위를 지정한다. devices.allow는 특정 장치를 사용 가능하게 한다.
+      </para>
+      <programlisting>
+       lxc.cgroup.cpuset.cpus = 0,1
+       lxc.cgroup.cpu.shares = 1234
+       lxc.cgroup.devices.deny = a
+       lxc.cgroup.devices.allow = c 1:3 rw
+       lxc.cgroup.devices.allow = b 8:0 rw
+      </programlisting>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Complex configuration -->복잡한 설정</title>
+      <para>
+        <!-- This example show a complex configuration making a complex
+      network stack, using the control groups, setting a new hostname,
+      mounting some locations and a changing root file system. -->
+        아래의 예제는 복잡한 네트워크 스택, 컨트롤 그룹 사용, 호스트 이름 설정, 몇몇 장소 마운트, 루트 파일시스템 변경 등의 복잡한 설정을 보여준다.
+      </para>
+      <programlisting>
+       lxc.utsname = complex
+       lxc.network.type = veth
+       lxc.network.flags = up
+       lxc.network.link = br0
+       lxc.network.hwaddr = 4a:49:43:49:79:bf
+       lxc.network.ipv4 = 10.2.3.5/24 10.2.3.255
+       lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
+       lxc.network.ipv6 = 2003:db8:1:0:214:5432:feab:3588
+       lxc.network.type = macvlan
+       lxc.network.flags = up
+       lxc.network.link = eth0
+       lxc.network.hwaddr = 4a:49:43:49:79:bd
+       lxc.network.ipv4 = 10.2.3.4/24
+       lxc.network.ipv4 = 192.168.10.125/24
+       lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3596
+       lxc.network.type = phys
+       lxc.network.flags = up
+       lxc.network.link = dummy0
+       lxc.network.hwaddr = 4a:49:43:49:79:ff
+       lxc.network.ipv4 = 10.2.3.6/24
+       lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3297
+       lxc.cgroup.cpuset.cpus = 0,1
+       lxc.cgroup.cpu.shares = 1234
+       lxc.cgroup.devices.deny = a
+       lxc.cgroup.devices.allow = c 1:3 rw
+       lxc.cgroup.devices.allow = b 8:0 rw
+       lxc.mount = /etc/fstab.complex
+       lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0
+       lxc.rootfs = /mnt/rootfs.complex
+       lxc.cap.drop = sys_module mknod setuid net_raw
+       lxc.cap.drop = mac_override
+      </programlisting>
+    </refsect2>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- See Also -->참조</title>
+    <simpara>
+      <citerefentry>
+       <refentrytitle><command>chroot</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>pivot_root</command></refentrytitle>
+       <manvolnum>8</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><filename>fstab</filename></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+
+      <citerefentry>
+       <refentrytitle><filename>capabilities</filename></refentrytitle>
+       <manvolnum>7</manvolnum>
+      </citerefentry>
+
+    </simpara>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/lxc.sgml.in b/doc/ko/lxc.sgml.in
new file mode 100644 (file)
index 0000000..45e4ed6
--- /dev/null
@@ -0,0 +1,875 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo>
+    <date>@LXC_GENERATE_DATE@</date>
+  </docinfo>
+
+
+  <refmeta>
+    <refentrytitle>lxc</refentrytitle>
+    <manvolnum>7</manvolnum>
+    <refmiscinfo>
+      Version @PACKAGE_VERSION@
+    </refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc</refname>
+
+    <refpurpose>
+      <!--
+      linux containers
+      -->
+      Linux 컨테이너
+    </refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title><!-- Quick start -->빠른 도움말</title>
+    <para>
+      <!--
+      You are in a hurry, and you don't want to read this man page. Ok,
+      without warranty, here are the commands to launch a shell inside
+      a container with a predefined configuration template, it may
+      work.
+      <command>@BINDIR@/lxc-execute -n foo -f
+      @DOCDIR@/examples/lxc-macvlan.conf /bin/bash</command>
+      -->
+      man 페이지를 읽고 싶지는 않지만 서둘러서 해보고 싶다면,
+      된다고 보장할 수는 없지만, 미리정의된 설정파일로 컨테이너 내에서 쉘을 실행하는 아래 명령어를 소개하고자 한다.
+
+      <command>@BINDIR@/lxc-execute -n foo -f
+      @DOCDIR@/examples/lxc-macvlan.conf /bin/bash</command>
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Overview -->개요</title>
+    <para>
+      <!--
+      The container technology is actively being pushed into the
+      mainstream linux kernel. It provides the resource management
+      through the control groups aka process containers and resource
+      isolation through the namespaces.
+      -->
+      컨테이너 기술은 리눅스 커널의 메인스트림에서 활발하게 개발이 진행되고 있다. 컨트롤 그룹(aka. 프로세스 컨테이너)을 통한 자원 관리와 네임스페이슬 통한 자원의 고립 기능을 제공한다.
+    </para>
+
+    <para>
+      <!--
+      The linux containers, <command>lxc</command>, aims to use these
+      new functionalities to provide a userspace container object
+      which provides full resource isolation and resource control for
+      an applications or a system.
+      -->
+      linux 컨테이너 (<command>lxc</command>)는 사용자영역 컨테이너 개체를 제공하는 새로운 기능을 사용하는 것을 목표로 하고 있다. 이 새로운 기능은 응용 프로그램이나 시스템에서 모든 자원의 격리와 제어를 제공한다.
+    </para>
+
+    <para>
+      <!--
+      The first objective of this project is to make the life easier
+      for the kernel developers involved in the containers project and
+      especially to continue working on the Checkpoint/Restart new
+      features. The <command>lxc</command> is small enough to easily
+      manage a container with simple command lines and complete enough
+      to be used for other purposes.
+      -->
+      이 프로젝트의 첫번째 목적은 컨테이너 프로젝트에 속해있는 커널 개발자들의 작업을 편하게 하며, 특히 새로운 기능인 Checkpoing/Restart에 대해 계속 작업을 진행해 나가는 것이다.
+      <command>lxc</command>는 작지만, 컨테이너를 간단한 명령어를 통해 쉽게 관리할 수 있고, 다목적으로 사용되기에도 충분하다.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Requirements -->요구사항</title>
+    <para>
+      <!--
+      The <command>lxc</command> relies on a set of functionalities
+      provided by the kernel which needs to be active. Depending of
+      the missing functionalities the <command>lxc</command> will
+      work with a restricted number of functionalities or will simply
+      fail.
+      -->
+      <command>lxc</command>는 커널이 제공하는 몇가지 기능들에 의존적이며, 해당 기능이 활성화되어 있어야 한다. 부족한 기능에 따라, 제한된 기능만이 동작하거나, 아예 동작을 안 할 수 있다.
+    </para>
+
+    <para>
+      <!--
+      The following list gives the kernel features to be enabled in
+      the kernel to have the full features container:
+      -->
+      아래 리스트는 컨테이너의 모든 기능을 사용하기 위해 활성화되어야 하는 커널 기능들이다.
+    </para>
+      <programlisting>
+           * General setup
+             * Control Group support
+               -> Namespace cgroup subsystem
+               -> Freezer cgroup subsystem
+               -> Cpuset support
+               -> Simple CPU accounting cgroup subsystem
+               -> Resource counters
+                 -> Memory resource controllers for Control Groups
+             * Group CPU scheduler
+               -> Basis for grouping tasks (Control Groups)
+             * Namespaces support
+               -> UTS namespace
+               -> IPC namespace
+               -> User namespace
+               -> Pid namespace
+               -> Network namespace
+           * Device Drivers
+             * Character devices
+               -> Support multiple instances of devpts
+             * Network device support
+               -> MAC-VLAN support
+               -> Virtual ethernet pair device
+           * Networking
+             * Networking options
+               -> 802.1d Ethernet Bridging
+           * Security options
+             -> File POSIX Capabilities
+      </programlisting>
+
+      <para>
+       <!--
+       The kernel version >= 2.6.32 shipped with the distros, will
+       work with <command>lxc</command>, this one will have less
+       functionalities but enough to be interesting.
+
+       The helper script <command>lxc-checkconfig</command> will give
+       you information about your kernel configuration.
+       -->
+       배포판들에 포함된 2.6.32 이상의 커널에서는  <command>lxc</command>가 동작한다. 매우 작은 기능만 있지만 충분히 사용할 수 있다.
+        <command>lxc-checkconfig</command> 스크립트를 사용하면 현재 커널 설정에 대한 정보를 얻을 수 있다.
+      </para>
+
+      <para>
+       <!--
+         The control group can be mounted anywhere, eg:
+         <command>mount -t cgroup cgroup /cgroup</command>.
+
+         It is however recommended to use cgmanager, cgroup-lite or systemd
+         to mount the cgroup hierarchy under /sys/fs/cgroup.
+        -->
+        컨트롤 그룹은 어디에든지 마운트될 수 있다. 예를 들어
+        <command>mount -t cgroup cgroup /cgroup</command>도 가능하다.
+
+        그러나 cgmanager, cgroup-lite 또는 systemd를 사용하여, /sys/fs/cgroup에 cgroup 계층구조를 마운트하는 것이 좋다.
+      </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Functional specification -->기능 사양</title>
+    <para>
+      <!--
+      A container is an object isolating some resources of the host,
+      for the application or system running in it.
+      -->
+      컨테이너는 응용프로그램이나 시스템을 내부에서 실행시키기 위해, 호스트의 몇몇 자원들을 격리시키는 객체이다.
+    </para>
+    <para>
+      <!--
+      The application / system will be launched inside a
+      container specified by a configuration that is either
+      initially created or passed as parameter of the starting
+      commands.
+      -->
+      어플리케이션/시스템은 처음 생성될때 또는 시작 명령어의 인자로 넘겨주었던 설정을 기반으로 한 컨테이너 안에서 실행된다.
+    </para>
+
+    <para>
+      <!--
+         How to run an application in a container ?
+       -->
+      어떻게 컨테이너 내부에서 응용 프로그램을 실행하는가?
+    </para>
+    <para>
+      <!--
+      Before running an application, you should know what are the
+      resources you want to isolate. The default configuration is to
+      isolate the pids, the sysv ipc and the mount points. If you want
+      to run a simple shell inside a container, a basic configuration
+      is needed, especially if you want to share the rootfs. If you
+      want to run an application like <command>sshd</command>, you
+      should provide a new network stack and a new hostname. If you
+      want to avoid conflicts with some files
+      eg. <filename>/var/run/httpd.pid</filename>, you should
+      remount <filename>/var/run</filename> with an empty
+      directory. If you want to avoid the conflicts in all the cases,
+      you can specify a rootfs for the container. The rootfs can be a
+      directory tree, previously bind mounted with the initial rootfs,
+      so you can still use your distro but with your
+      own <filename>/etc</filename> and <filename>/home</filename>
+      -->
+      어플리케이션을 실행하기에 앞서, 고립시키고 싶은 자원을 먼저 알아야 한다. 기본 설정은 pid와 sysv ipc 그리고 마운트 포인트들을 고립시킨다.
+      만약에 간단한 쉘을 컨테이너 내부에서 실행시키기 원한다면, 특히 rootfs를 공유하고 싶다면 매우 기초적인 설정이 요구된다.
+      <command>sshd</command> 같은 응용 프로그램을 실행시키고 싶다면, 새로운 네트워크 스택과 호스트네임을 제공해 주어야 한다.
+      만약 몇몇 파일들, 예를 들어, <filename>/var/run/httpd.pid</filename>이 충돌나는것을 막고 싶다면, <filename>/var/run</filename>를 빈 디렉토리로 다시 마운트하는 것이 필요하다.
+      모든 경우의 파일 충돌을 피하고 싶다면, 컨테이너를 위한 루트 파일시스템를 따로 지정해 줄 수도 있다. 루트 파일시스템은 미리 원래의 루트 파일시스템을 바인드 마운트한 디렉토리가 될 수도 있다. 이렇게 되면 자신만의 <filename>/etc</filename>, <filename>/home</filename>을 사용하면서도 배포판을 그대로 사용할 수 있다.
+    </para>
+    <para>
+      <!--
+      Here is an example of directory tree
+      for <command>sshd</command>:
+      <programlisting> 
+[root@lxc sshd]$ tree -d rootfs
+       
+rootfs 
+|&#045;&#045; bin      
+|&#045;&#045; dev      
+|   |&#045;&#045; pts
+|   `&#045;&#045; shm
+|       `&#045;&#045; network
+|&#045;&#045; etc      
+|   `&#045;&#045; ssh
+|&#045;&#045; lib      
+|&#045;&#045; proc
+|&#045;&#045; root
+|&#045;&#045; sbin
+|&#045;&#045; sys      
+|&#045;&#045; usr      
+`&#045;&#045; var      
+    |&#045;&#045; empty
+    |   `&#045;&#045; sshd
+    |&#045;&#045; lib
+    |   `&#045;&#045; empty
+    |       `&#045;&#045; sshd
+    `&#045;&#045; run
+        `&#045;&#045; sshd
+      </programlisting>
+
+      and the mount points file associated with it:
+      <programlisting>
+       [root@lxc sshd]$ cat fstab
+
+       /lib /home/root/sshd/rootfs/lib none ro,bind 0 0
+       /bin /home/root/sshd/rootfs/bin none ro,bind 0 0
+       /usr /home/root/sshd/rootfs/usr none ro,bind 0 0
+       /sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
+      </programlisting>
+      -->
+       아래는 <command>sshd</command>를 사용하기 위한 디렉토리 트리 예제이다.
+      <programlisting> 
+[root@lxc sshd]$ tree -d rootfs
+       
+rootfs 
+|-- bin        
+|-- dev        
+|   |-- pts
+|   `-- shm
+|       `-- network
+|-- etc        
+|   `-- ssh
+|-- lib        
+|-- proc
+|-- root
+|-- sbin
+|-- sys        
+|-- usr        
+`-- var        
+    |-- empty
+    |   `-- sshd
+    |-- lib
+    |   `-- empty
+    |       `-- sshd
+    `-- run
+        `-- sshd
+      </programlisting>
+
+      그리고, 해당 마운트 포인트 파일의 내용은 아래와 같다.
+      <programlisting>
+       [root@lxc sshd]$ cat fstab
+
+       /lib /home/root/sshd/rootfs/lib none ro,bind 0 0
+       /bin /home/root/sshd/rootfs/bin none ro,bind 0 0
+       /usr /home/root/sshd/rootfs/usr none ro,bind 0 0
+       /sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
+      </programlisting>
+    </para>
+
+    <para>
+      <!--
+      How to run a system in a container ?
+      -->
+      어떻게 컨테이너 내에서 시스템을 실행하는가?
+    </para>
+
+    <para>
+      <!--
+      Running a system inside a container is paradoxically easier
+    than running an application. Why ? Because you don't have to care
+    about the resources to be isolated, everything need to be
+    isolated, the other resources are specified as being isolated but
+    without configuration because the container will set them
+    up. eg. the ipv4 address will be setup by the system container
+    init scripts. Here is an example of the mount points file:
+
+      <programlisting>
+       [root@lxc debian]$ cat fstab
+
+       /dev    /home/root/debian/rootfs/dev none bind 0 0
+       /dev/pts /home/root/debian/rootfs/dev/pts  none bind 0 0
+      </programlisting>
+
+      More information can be added to the container to facilitate the
+      configuration. For example, make accessible from the container
+      the resolv.conf file belonging to the host.
+
+      <programlisting>
+       /etc/resolv.conf /home/root/debian/rootfs/etc/resolv.conf none bind 0 0
+      </programlisting>
+      -->
+      컨테이너 내에서 시스템을 실행하는 것은 역설적으로 어플리케이션을 실행하는 것보다 쉽다. 왜 그럴까? 왜냐하면, 어떤 자원이 고립되어야 하는지 고려할 필요가 없다. 모든 자원이 고립되면 된다. 자원들은 별다른 설정없이 고립된다고 지정만 해도 된다. 왜냐하면 컨테이너가 그 자원들을 세팅할 것이기 때문이다. 예를 들어 ipv4 주소는 시스템 컨테이너의 init 스크립트들을 통해 세팅된다. 아래는 마운트 포인트 파일의 예제이다.
+
+      <programlisting>
+       [root@lxc debian]$ cat fstab
+
+       /dev    /home/root/debian/rootfs/dev none bind 0 0
+       /dev/pts /home/root/debian/rootfs/dev/pts  none bind 0 0
+      </programlisting>
+
+      설정을 돕기 위해서 컨테이너에 부가 정보를 추가할 수 있다. 아래와 같이 호스트에 있는 resolv.conf를 컨테이너 안에서 접근할 수 있다.
+
+      <programlisting>
+       /etc/resolv.conf /home/root/debian/rootfs/etc/resolv.conf none bind 0 0
+      </programlisting>
+    </para>
+
+    <refsect2>
+      <title><!-- Container life cycle -->컨테이너의 생명주기</title>
+      <para>
+       <!--
+       When the container is created, it contains the configuration
+       information. When a process is launched, the container will be
+       starting and running. When the last process running inside the
+       container exits, the container is stopped.
+       -->
+        컨테이너가 생성될때, 컨테이너는 설정정보를 포함하게 된다.
+        프로세스가 실행될때, 컨테이너는 시작되고 실행된다.
+        컨테이너 내에서 실행되던 마지막 프로세스가 종료되면, 컨테이너는 종료된다.
+      </para>
+      <para>
+       <!--
+       In case of failure when the container is initialized, it will
+       pass through the aborting state.
+       -->
+        컨테이너의 초기화가 실패했을 경우, (아래 그림처럼)중단 상태로 바뀌게 된다.
+      </para>
+
+      <programlisting>
+<![CDATA[
+   ---------
+  | STOPPED |<---------------
+   ---------                 |
+       |                     |
+     start                   |
+       |                     |
+       V                     |
+   ----------                |
+  | STARTING |--error-       |
+   ----------         |      |
+       |              |      |
+       V              V      |
+   ---------    ----------   |
+  | RUNNING |  | ABORTING |  |
+   ---------    ----------   |
+       |              |      |
+  no process          |      |
+       |              |      |
+       V              |      |
+   ----------         |      |
+  | STOPPING |<-------       |
+   ----------                |
+       |                     |
+        ---------------------
+]]>
+      </programlisting>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Configuration -->설정</title>
+      <para>
+       <!--
+       The container is configured through a configuration
+       file, the format of the configuration file is described in
+      <citerefentry>
+       <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+      -->
+      </para>
+        컨테이너는 설정파일에 의해서 설정된다. 설정파일의 형식은 다음을 참조하면 된다.
+      <citerefentry>
+       <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+    </refsect2>
+
+    <refsect2>
+      <title><!--Creating / Destroying container
+       (persistent container) -->컨테이너의 생성/제거 (지속 컨테이너)</title>
+      <para>
+       <!--
+       A persistent container object can be
+       created via the <command>lxc-create</command>
+       command. It takes a container name as parameter and
+       optional configuration file and template.
+       The name is used by the different
+       commands to refer to this
+       container. The <command>lxc-destroy</command> command will
+       destroy the container object.
+       <programlisting>
+         lxc-create -n foo
+         lxc-destroy -n foo
+       </programlisting>
+       -->
+        지속성 컨테이너 객체는 <command>lxc-create</command> 명령어로 생성된다.         컨테이너이름을 인수로 받으며, 부가적인 설정파일과 템플릿을 지정한다.
+        여기서 지정하는 이름은 다른 명령어들을 사용할 때 해당 컨테이너를 참조하기 위해 사용된다. <command>lxc-destroy</command> 명령어는 컨테이너 객체를 제거한다.
+       <programlisting>
+         lxc-create -n foo
+         lxc-destroy -n foo
+       </programlisting>
+      </para>
+    </refsect2>
+
+    <refsect2>
+       <title><!-- Volatile container -->휘발성 컨테이너</title>
+       <para>
+          <!--
+          It is not mandatory to create a container object
+       before to start it.
+       The container can be directly started with a
+       configuration file as parameter.
+        -->
+          컨테이너 시작전에 컨테이너 오브젝트를 생성하는 것이 의무는 아니다.
+          컨테이너는 설정파일을 파라미터로 넣어서 바로 시작할 수도 있다.
+       </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Starting / Stopping container -->컨테이너의 시작과 종료</title>
+      <para>
+        <!--
+        When the container has been created, it is ready to run an
+      application / system.
+      This is the purpose of the <command>lxc-execute</command> and
+      <command>lxc-start</command> commands.
+      If the container was not created before
+      starting the application, the container will use the
+      configuration file passed as parameter to the command,
+      and if there is no such parameter either, then
+      it will use a default isolation.
+      If the application is ended, the container will be stopped also,
+      but if needed the <command>lxc-stop</command> command can
+      be used to kill the still running application.
+      -->
+        컨테이너가 생성하면 응용 프로그램/시스템이 실행될 준비를 마친 것이다.
+        실행하는 것이 바로 <command>lxc-execute</command>와 <command>lxc-start</command> 명령어의 목적이다.
+        응용프로그램 시작전에 컨테이너가 생성되어 있지 않다면, 컨테이너는 명령어의 인수로 넘겼던 설정파일을 사용한다. 그런 인수마저 없다면, 기본 고립 환경을 사용한다.
+        만약 응용프로그램이 종료되면, 컨테이너도 역시 종료된다. 실행중인 응용프로그램을 종료시키고 싶다면 <command>lxc-stop</command>를 사용하면 된다.
+      </para>
+
+      <para>
+        <!--
+       Running an application inside a container is not exactly the
+       same thing as running a system. For this reason, there are two
+       different commands to run an application into a container:
+       <programlisting>
+         lxc-execute -n foo [-f config] /bin/bash
+         lxc-start -n foo [-f config] [/bin/bash]
+       </programlisting>
+        -->
+        컨테이너 내부에서 응용프로그램을 실행하는 것은 시스템을 실행하는 것과는 차이가 있다. 이런 이유로 아래의 두가지 명령어가 사용된다.
+        <programlisting>
+         lxc-execute -n foo [-f config] /bin/bash
+         lxc-start -n foo [-f config] [/bin/bash]
+       </programlisting>
+      </para>
+
+      <para>
+        <!--
+       <command>lxc-execute</command> command will run the
+       specified command into the container via an intermediate
+       process, <command>lxc-init</command>.
+       This lxc-init after launching  the specified command,
+       will wait for its end and all other reparented processes.
+        (to support daemons in the container).
+       In other words, in the
+       container, <command>lxc-init</command> has the pid 1 and the
+       first process of the application has the pid 2.
+        -->
+        <command>lxc-execute</command> 명령어는 컨테이너 내부에서 <command>lxc-init</command> 프로세스를 통해 실행할 명령어를 지정할 수 있다.
+        lxc-init는 지정한 명령어를 실행한 후, 그 명령어로 실행된 모든 프로세스들이 종료되기를 기다린다. (컨테이너 내부에서 데몬을 지원하기 위해서이다)
+        다시 말해서, 컨테이너 내부에서 <command>lxc-init</command>는 1번 pid를 갖고, 응용프로그램의 첫번째 프로세스는 2번 pid를 가진다.
+      </para>
+
+      <para>
+        <!--
+       <command>lxc-start</command> command will run directly the specified
+       command into the container.
+       The pid of the first process is 1. If no command is
+       specified <command>lxc-start</command> will
+       run the command defined in lxc.init_cmd or if not set,
+       <filename>/sbin/init</filename> .
+        -->
+        <command>lxc-start</command> 명령어는 지정한 명령어를 컨테이너 내에서 직접 실행한다. 첫 프로세스의 pid는 1번이다. 만약 어떤 명령어도 지정되지 않으면, lxc.init_cmd에 지정된 명령어를 실행한다. 이마저도 지정되있지 않으면, <filename>/sbin/init</filename>를 실행한다.
+      </para>
+
+      <para>
+        <!--
+       To summarize, <command>lxc-execute</command> is for running
+       an application and <command>lxc-start</command> is better suited for
+       running a system.
+        -->
+        요약하자면, <command>lxc-execute</command>는 응용 프로그램 실행을 위해서, <command>lxc-start</command>는 시스템 실행을 위해 적합하다.
+      </para>
+
+      <para>
+        <!--
+       If the application is no longer responding, is inaccessible or is
+       not able to finish by itself, a
+       wild <command>lxc-stop</command> command will kill all the
+       processes in the container without pity.
+       <programlisting>
+         lxc-stop -n foo
+       </programlisting>
+        -->
+        만약 어플리케이션이 더이상 응답하지 않거나, 접근이 불가능하거나, 스스로 종료되지 못할 경우, <command>lxc-stop</command> 명령어는 컨테이너 내의 모든 프로세스들을 가차없이 종료시킬 것이다.
+        <programlisting>
+          lxc-stop -n foo
+        </programlisting>
+      </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Connect to an available tty -->사용가능한 tty 접속</title>
+      <para>
+        <!--
+       If the container is configured with the ttys, it is possible
+       to access it through them. It is up to the container to
+       provide a set of available tty to be used by the following
+       command. When the tty is lost, it is possible to reconnect it
+       without login again.
+       <programlisting>
+         lxc-console -n foo -t 3
+       </programlisting>
+        -->
+        컨테이너에 tty가 설정되어 있다면, tty를 통해 컨테이너에 접근할 수 있다.
+        아래 명령어를 통해 사용될 가능한 tty를 제공하는 것은 컨테이너에 달려있다.
+        tty가 종료되었을 때는 다시 로그인하지 않고도 재접속할 수 있다.
+       <programlisting>
+         lxc-console -n foo -t 3
+       </programlisting>
+      </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Freeze / Unfreeze container -->컨테이너 동결/동결 해제</title>
+      <para>
+        <!--
+       Sometime, it is useful to stop all the processes belonging to
+       a container, eg. for job scheduling. The commands:
+       <programlisting>
+         lxc-freeze -n foo
+       </programlisting>
+
+       will put all the processes in an uninteruptible state and
+
+       <programlisting>
+         lxc-unfreeze -n foo
+       </programlisting>
+
+       will resume them.
+        -->
+        스케줄링 등을 위해 컨테이너에 속해있는 모든 프로세스를 정지 시키는 것은 때로 유용할 수 있다. 아래 명령어들을 사용하면 된다.
+
+       <programlisting>
+         lxc-freeze -n foo
+       </programlisting>
+        는 모든 프로세스들을 인터럽트 불가능한 상태로 만든다.
+
+       <programlisting>
+         lxc-unfreeze -n foo
+       </programlisting>
+        는 모든 프로세스를 정지 해제 시킨다.
+      </para>
+
+      <para>
+        <!--
+       This feature is enabled if the cgroup freezer is enabled in the
+       kernel.
+        -->
+        이 기능은 커널에서 cgroup freezer 기능이 활성화 되어 있어야 사용 가능하다.
+      </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Getting information about container -->
+        컨테이너 관련 정보 얻어오기</title>
+      <para>
+        <!--
+        When there are a lot of containers, it is hard to follow
+      what has been created or destroyed, what is running or what are
+      the pids running into a specific container. For this reason, the
+      following commands may be useful:
+       <programlisting>
+         lxc-ls
+         lxc-info -n foo
+       </programlisting>
+        -->
+        컨테이너가 많이 존재하는 경우, 어떤 것이 생성되고 제거됬는지, 어떤 것이 실행 중인지 또는 어떤 프로세스들이 특정 컨테이너 내에서 실행되는지를 따라가기 힘들다. 이를 위해 다음과 같은 명령어들이 유용하게 사용될 수 있다.
+       <programlisting>
+         lxc-ls
+         lxc-info -n foo
+       </programlisting>
+      </para>
+      <para>
+        <!--
+       <command>lxc-ls</command> lists the containers of the
+       system.
+        -->
+        <command>lxc-ls</command>는 시스템의 컨테이너들의 리스트를 표시한다.
+      </para>
+
+      <para>
+        <!--
+       <command>lxc-info</command> gives information for a specific
+       container.
+        -->
+        <command>lxc-info</command>는 지정한 컨테이너의 정보를 얻어온다.
+      </para>
+
+      <para>
+        <!--
+       Here is an example on how the combination of these commands
+       allows one to list all the containers and retrieve their state.
+       <programlisting>
+         for i in $(lxc-ls -1); do
+           lxc-info -n $i
+         done
+       </programlisting>
+        -->
+        아래는 명령어들을 조합하여 컨테이너들의 리스트를 얻어오고 상태를 출력하는 예제이다.
+       <programlisting>
+         for i in $(lxc-ls -1); do
+           lxc-info -n $i
+         done
+       </programlisting>
+      </para>
+
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Monitoring container -->컨테이너 모니터링</title>
+      <para>
+        <!--
+        It is sometime useful to track the states of a container,
+      for example to monitor it or just to wait for a specific
+      state in a script.
+        -->
+        컨테이너의 상태를 추적하는 것은 때때로 매우 유용하다.
+        예를 들어, 상태를 모니터링하거나, 스크립트에서 특정상태를 기다리는 경우이다.
+      </para>
+
+      <para>
+        <!--
+       <command>lxc-monitor</command> command will monitor one or
+       several containers. The parameter of this command accept a
+       regular expression for example:
+       <programlisting>
+         lxc-monitor -n "foo|bar"
+       </programlisting>
+       will monitor the states of containers named 'foo' and 'bar', and:
+       <programlisting>
+         lxc-monitor -n ".*"
+       </programlisting>
+       will monitor all the containers.
+        -->
+        <command>lxc-monitor</command> 명령어는 하나 또는 여러개의 컨테이너들을 모니터링한다. 이 명령어의 인수로 정규표현식을 넘길 수도 있다.
+        예를 들면,
+       <programlisting>
+         lxc-monitor -n "foo|bar"
+       </programlisting>
+        는 'foo'와 'bar'라는 이름의 컨테이너의 상태 변화를 모니터링한다. 그리고,
+       <programlisting>
+         lxc-monitor -n ".*"
+       </programlisting>
+        는 모든 컨테이너를 모니터링한다.
+      </para>
+      <para>
+        <!--
+       For a container 'foo' starting, doing some work and exiting,
+       the output will be in the form:
+       <programlisting>
+         'foo' changed state to [STARTING]
+         'foo' changed state to [RUNNING]
+         'foo' changed state to [STOPPING]
+         'foo' changed state to [STOPPED]
+       </programlisting>
+        -->
+        'foo' 컨테이너가 시작되고 몇 가지 작업을 수행하고 종료된 경우,
+        출력은 다음과 같다.
+       <programlisting>
+         'foo' changed state to [STARTING]
+         'foo' changed state to [RUNNING]
+         'foo' changed state to [STOPPING]
+         'foo' changed state to [STOPPED]
+       </programlisting>
+      </para>
+      <para>
+        <!--
+       <command>lxc-wait</command> command will wait for a specific
+       state change and exit. This is useful for scripting to
+       synchronize the launch of a container or the end. The
+       parameter is an ORed combination of different states. The
+       following example shows how to wait for a container if he went
+       to the background.
+
+       <programlisting>
+<![CDATA[
+         # launch lxc-wait in background
+         lxc-wait -n foo -s STOPPED &
+         LXC_WAIT_PID=$!
+
+         # this command goes in background
+         lxc-execute -n foo mydaemon &
+
+         # block until the lxc-wait exits
+         # and lxc-wait exits when the container
+         # is STOPPED
+         wait $LXC_WAIT_PID
+         echo "'foo' is finished"
+]]>
+       </programlisting>
+        -->
+        <command>lxc-wait</command> 명령어는 지정한 상태로 변화되는 것을 기다린다. 이 명령어는 컨테이너의 시작이나 종료와 동기화되는 스크립트를 작성할 때 유용하다.
+        인수는 다른 상태들을 OR로 묶어서 지정해 줄 수 있다. 아래 예제는 백그라운드에서 어떻게 컨테이너의 상태 변화를 기다리는지 보여준다.
+       <programlisting>
+<![CDATA[
+         # launch lxc-wait in background
+         lxc-wait -n foo -s STOPPED &
+         LXC_WAIT_PID=$!
+
+         # this command goes in background
+         lxc-execute -n foo mydaemon &
+
+         # block until the lxc-wait exits
+         # and lxc-wait exits when the container
+         # is STOPPED
+         wait $LXC_WAIT_PID
+         echo "'foo' is finished"
+]]>
+       </programlisting>
+      </para>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Setting the control group for container -->
+        컨테이너 컨트롤 그룹 설정
+      </title>
+      <para>
+        <!--
+        The container is tied with the control groups, when a
+       container is started a control group is created and associated
+       with it. The control group properties can be read and modified
+       when the container is running by using the lxc-cgroup command.
+        -->
+        컨테이너는 컨트롤 그룹과 결합되어 있다.
+        컨테이너가 시작되면 컨트롤그룹이 만들어지고 해당 컨트롤 그룹과 연결된다.
+        컨테이너가 실행중일 때, lxc-cgroup 명령어를 이용해 컨트롤 그룹 속성은 읽거나 수정될 수 있다.
+      </para>
+      <para>
+        <!--
+       <command>lxc-cgroup</command> command is used to set or get a
+       control group subsystem which is associated with a
+       container. The subsystem name is handled by the user, the
+       command won't do any syntax checking on the subsystem name, if
+       the subsystem name does not exists, the command will fail.
+        -->
+        <command>lxc-cgroup</command> 명령어는 컨테이너와 연결된 컨트롤 그룹 서브시스템의 값을 얻어오거나 설정한다.
+        서브시스템의 이름은 사용자가 결정하며, 이 명령어는 이름이 적합한지 여부를 검사하지 않는다.
+       만약 서브시스템의 이름이 없다면 명령어는 실패할 것이다.
+      </para>
+      <para>
+        <!--
+       <programlisting>
+         lxc-cgroup -n foo cpuset.cpus
+       </programlisting>
+       will display the content of this subsystem.
+       <programlisting>
+         lxc-cgroup -n foo cpu.shares 512
+       </programlisting>
+       will set the subsystem to the specified value.
+        -->
+       <programlisting>
+         lxc-cgroup -n foo cpuset.cpus
+       </programlisting>
+        는 해당 서브시스템의 내용을 표시한다.
+       <programlisting>
+         lxc-cgroup -n foo cpu.shares 512
+       </programlisting>
+        는 해당 서브시스템의 값을 설정한다.
+      </para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title><!-- Bugs -->버그</title>
+    <para>
+      <!--
+      The <command>lxc</command> is still in development, so the
+    command syntax and the API can change. The version 1.0.0 will be
+    the frozen version.
+      -->
+      <command>lxc</command>는 아직 개발중이다. 그래서 명령어 사용법이나, API가 변경될 수 있다. 버전 1.0.0은 변경되지 않는 고정된 버전이다.
+    </para>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file Local variables: mode:
+sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t sgml-indent-step:2 sgml-indent-data:t
+sgml-parent-document:nil sgml-default-dtd-file:nil
+sgml-exposed-tags:nil sgml-local-catalogs:nil
+sgml-local-ecat-files:nil End: -->
diff --git a/doc/ko/lxc.system.conf.sgml.in b/doc/ko/lxc.system.conf.sgml.in
new file mode 100644 (file)
index 0000000..ea8451e
--- /dev/null
@@ -0,0 +1,243 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Ltd. 2014
+
+Authors:
+Stéphane Graber <stgraber@ubuntu.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae Yoo <sungbae.yoo at samsung.com>
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc.system.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc.system.conf</refname>
+
+    <refpurpose>
+      <!--
+      LXC system configuration file
+      -->
+      LXC 시스템 설정파일
+    </refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title><!-- Description -->설명</title>
+
+    <para>
+      <!--
+      The system configuration is located at
+      <filename>@LXC_GLOBAL_CONF@</filename> or
+      <filename>~/.config/lxc/lxc.conf</filename> for unprivileged
+      containers.
+      -->
+      시스템 설정은 <filename>@LXC_GLOBAL_CONF@</filename>에 위치하고 있다. 비
+특권 컨테이너의 경우는 <filename>~/.config/lxc/lxc.conf</filename>에 위치하고 있
+다.
+    </para>
+
+    <para>
+      <!--
+      This configuration file is used to set values such as default
+      lookup paths and storage backend settings for LXC.
+      -->
+      이 설정파일은 LXC 기본 경로 및 저장소 백엔드 설정과 같은 값들을 설정할 때 사용한다.
+    </para>
+
+    <refsect2>
+      <title><!-- Configuration paths -->경로 설정</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.lxcpath</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              The location in which all containers are stored.
+              -->
+              모든 컨테이너들이 저장되는 장소.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.default_config</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              The path to the default container configuration.
+              -->
+              컨테이너의 기본 설정파일 경로.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title><!-- Control Groups -->컨트롤 그룹</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.cgroup.use</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Comma separated list of cgroup controllers to setup.
+              If none is specified, all available controllers will be used.
+              -->
+              사용할 cgroup 컨트롤러의 쉼표(,)로 구분된 목록.
+              아무것도 지정하지 않았다면, 사용가능한 컨트롤러 전체를 사용될 것이다.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.cgroup.pattern</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Format string used to generate the cgroup path (e.g. lxc/%n).
+              -->
+              컨테이너용 cgroup을 생성할 때 사용하는 포맷 문자열 (예 : lxc/%n).
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>LVM</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.bdev.lvm.vg</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Default LVM volume group name.
+              -->
+              기본 LVM 볼륨 그룹 이름
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.bdev.lvm.thin_pool</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Default LVM thin pool name.
+              -->
+              기본 LVM thin pool 이름
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>ZFS</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.bdev.zfs.root</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              Default ZFS root name.
+              -->
+              기본 ZFS root 이름.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <simpara>
+      <citerefentry>
+        <refentrytitle><command>lxc</command></refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc.container.conf</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc.system.conf</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle><command>lxc-usernet</command></refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry>
+    </simpara>
+  </refsect1>
+
+  &seealso;
+
+  <refsect1>
+    <title><!-- Author -->저자</title>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/ko/see_also.sgml.in b/doc/ko/see_also.sgml.in
new file mode 100644 (file)
index 0000000..b2fa48a
--- /dev/null
@@ -0,0 +1,121 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright IBM Corp. 2007, 2008
+
+Authors:
+Daniel Lezcano <daniel.lezcano at free.fr>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Translated into Korean
+by Sungbae yoo <sungbae.yoo at samsung.com>
+
+-->
+
+  <refsect1>
+    <title><!--See Also-->참조</title>
+
+    <simpara>
+      <citerefentry>
+       <refentrytitle><command>lxc</command></refentrytitle>
+       <manvolnum>7</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-create</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-copy</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-destroy</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-start</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-stop</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-execute</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-console</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-monitor</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-wait</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-cgroup</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-ls</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-info</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-freeze</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-unfreeze</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc-attach</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
+       <refentrytitle><command>lxc.conf</command></refentrytitle>
+       <manvolnum>5</manvolnum>
+      </citerefentry>
+
+    </simpara>
+
+  </refsect1>
+
index 8535c3d..c1937d9 100644 (file)
@@ -78,6 +78,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       inside the container or the container does not have a working
       nsswitch mechanism.
     </para>
+    <para>
+    Previous versions of <command>lxc-attach</command> simply attached to the
+    specified namespaces of a container and ran a shell or the specified command
+    without first allocating a pseudo terminal. This made them vulnerable to
+    input faking via a TIOCSTI <command>ioctl</command> call after switching
+    between userspace execution contexts with different privilege levels. Newer
+    versions of <command>lxc-attach</command> will try to allocate a pseudo
+    terminal master/slave pair on the host and attach any standard file
+    descriptors which refer to a terminal to the slave side of the pseudo
+    terminal before executing a shell or command. Note, that if none of the
+    standard file descriptors refer to a terminal <command>lxc-attach</command>
+    will not try to allocate a pseudo terminal. Instead it will simply attach
+    to the containers namespaces and run a shell or the specified command.
+    </para>
 
   </refsect1>
 
@@ -126,7 +140,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <replaceable>CGROUP|LSM</replaceable>. Allowed values are
       <replaceable>CGROUP</replaceable>, <replaceable>CAP</replaceable> and
       <replaceable>LSM</replaceable> representing cgroup, capabilities and
-      restriction privileges respectively.
+      restriction privileges respectively. (The pipe symbol needs to be escaped,
+      e.g. <replaceable>CGROUP\|LSM</replaceable> or quoted, e.g.
+      <replaceable>"CGROUP|LSM"</replaceable>.)
     </para>
          <para>
            <emphasis>Warning:</emphasis> This may leak privileges into the
@@ -154,7 +170,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
            <replaceable>NETWORK</replaceable>. This allows one to change
            the context of the process to e.g. the network namespace of the
            container while retaining the other namespaces as those of the
-           host.
+            host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
          </para>
          <para>
            <emphasis>Important:</emphasis> This option implies
@@ -306,11 +324,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       network/pid namespace context of the attached process. In order
       not to interfere with the host's actual filesystem, the mount
       namespace will be unshared (like <command>lxc-unshare</command>
-      does) before this is done, esentially giving the process a new
+      does) before this is done, essentially giving the process a new
       mount namespace, which is identical to the hosts's mount namespace
       except for the <replaceable>/proc</replaceable> and
       <replaceable>/sys</replaceable> filesystems.
     </para>
+    <para>
+      Previous versions of <command>lxc-attach</command> suffered a bug whereby
+      a user could attach to a containers namespace without being placed in a
+      writeable cgroup for some critical subsystems. Newer versions of
+      <command>lxc-attach</command> will check whether a user is in a writeable
+      cgroup for those critical subsystems. <command>lxc-attach</command> might
+      thus fail unexpectedly for some users (E.g. on systems where an
+      unprivileged user is not placed in a writeable cgroup in critical
+      subsystems on login.). However, this behavior is correct and more secure.
+    </para>
   </refsect1>
 
   <refsect1>
index cb58074..f53e9fc 100644 (file)
@@ -82,7 +82,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option>-D <replacable>PATH</replacable>, --checkpoint-dir=<replacable>PATH</replacable></option>
+          <option>-D <replaceable>PATH</replaceable>, --checkpoint-dir=<replaceable>PATH</replaceable></option>
         </term>
         <listitem>
           <para>
index 11b26b8..f134b80 100644 (file)
@@ -58,6 +58,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
       <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
       <arg choice="req">-o <replaceable>orig</replaceable></arg>
       <arg choice="req">-n <replaceable>new</replaceable></arg>
       <arg choice="opt">-- hook arguments</arg>
@@ -72,6 +73,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <arg choice="opt">-L <replaceable>fssize</replaceable></arg>
       <arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
+      <arg choice="opt">-R </arg>
       <arg choice="req">orig</arg>
       <arg choice="req">new</arg>
       <arg choice="opt">-- hook arguments</arg>
@@ -219,6 +221,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
+         <option>-R, --rename</option>
+       </term>
+       <listitem>
+         <para>
+           Rename an existing container.
+           <replaceable>orig</replaceable> is renamed <replaceable>new</replaceable>.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
          <option>-o, --orig <replaceable>orig</replaceable></option>
        </term>
        <listitem>
@@ -261,6 +275,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     </para>
   </refsect1>
 
+  <refsect1>
+    <title>Notes</title>
+    <para>
+    <command>lxc-clone</command> is deprecated in favor of
+    <command>lxc-copy</command>.
+    </para>
+  </refsect1>
+
   &seealso;
 
   <refsect1>
index fd4caa6..8f0bb1f 100644 (file)
@@ -96,7 +96,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-e <optional><replaceable>escape character</replaceable></optional></option>
+         <option>-e, --escape <replaceable>escape character</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -109,7 +109,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
       <varlistentry>
        <term>
-         <option>-t <optional><replaceable>ttynum</replaceable></optional></option>
+         <option>-t, --tty <replaceable>ttynum</replaceable></option>
        </term>
        <listitem>
          <para>
diff --git a/doc/lxc-copy.sgml.in b/doc/lxc-copy.sgml.in
new file mode 100644 (file)
index 0000000..956939f
--- /dev/null
@@ -0,0 +1,312 @@
+<!--
+
+lxc: linux Container library
+
+(C) Copyright Canonical Inc. 2007, 2008
+
+Authors:
+Christian Brauner <christian.brauner at mailbox.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+-->
+
+<!DOCTYPE refentry PUBLIC @docdtd@ [
+
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
+<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
+]>
+
+<refentry>
+
+  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
+
+  <refmeta>
+    <refentrytitle>lxc-copy</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>lxc-copy</refname>
+
+    <refpurpose>
+      copy an existing container.
+    </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-e, --ephemeral</arg>
+      <arg choice="opt">-B, --backingstorage <replaceable>backingstorage</replaceable></arg>
+      <arg choice="opt">-s, --snapshot</arg>
+      <arg choice="opt">-K, --keepdata</arg>
+      <arg choice="opt">-M, --keepmac</arg>
+      <arg choice="opt">-L, --fssize <replaceable>size [unit]</replaceable></arg>
+      <arg choice="opt">-- hook arguments</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>lxc-copy</command>
+      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
+      <arg choice="opt">-P, --lxcpath <replaceable>path</replaceable></arg>
+      <arg choice="req">-N, --newname <replaceable>newname</replaceable></arg>
+      <arg choice="opt">-p, --newpath <replaceable>newpath</replaceable></arg>
+      <arg choice="req">-R, --rename</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>
+      <command>lxc-copy</command> creates and optionally starts (ephemeral or
+      non-ephemeral) copies of existing containers. It replaces
+      <command>lxc-clone</command> and <command>lxc-start-ephemeral</command>.
+    </para>
+    <para>
+      <command>lxc-copy</command> creates copies of existing containers. Copies
+      can be complete clones of the original container. In this case the whole
+      root filesystem of the container is simply copied to the new container. Or
+      they can be snapshots, i.e. small copy-on-write copies of the original
+      container. In this case the specified backing storage for the copy must
+      support snapshots. This currently includes aufs, btrfs, lvm (lvm devices
+      do not support snapshots of snapshots.), overlay, and zfs.
+    </para>
+      
+    <para>
+    The copy's backing storage will be of the same type as the original
+    container. aufs or overlayfs snapshots of directory backed containers are
+    exempted from this rule.
+    </para>
+
+    <para>
+    When the <replaceable>-e</replaceable> flag is specified an ephemeral
+    snapshot of the original container is created and started. Ephemeral
+    containers will have <command>lxc.ephemeral = 1</command> set in their
+    config file and will be destroyed on shutdown. When
+    <replaceable>-e</replaceable> is used in combination with
+    <replaceable>-D</replaceable> a non-ephemeral snapshot of the original
+    container is created and started.</para>
+
+    <para>
+    When <replaceable>-e</replaceable> is specified and no newname is given via
+    <replaceable>-N</replaceable> a random name for the snapshot will be chosen.
+    </para>
+
+    <para>
+    Containers created and started with <replaceable>-e</replaceable> can have
+    custom mounts. These are specified with the <replaceable>-m</replaceable>
+    flag. Currently three types of mounts are supported:
+    <replaceable>aufs</replaceable>, <replaceable>bind</replaceable>, and
+    <replaceable>overlay</replaceable>. Mount types are specified as suboptions
+    to the <replaceable>-m</replaceable> flag and can be specified multiple
+    times separated by commas. <replaceable>aufs</replaceable> and
+    <replaceable>overlay</replaceable> mounts are currently specified in the
+    format <replaceable>-m overlay=/src:/dest</replaceable>.  When no
+    destination <replaceable>dest</replaceable> is specified
+    <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. Read-only <replaceable>bind</replaceable>
+    mounts are specified <replaceable>-m bind=/src:/dest:ro</replaceable> and
+    read-write <replaceable>bind</replaceable> mounts <replaceable>-m
+    bind=/src:/dest:rw</replaceable>. Read-write <replaceable>bind</replaceable>
+    mounts are the default and <replaceable>rw</replaceable> can be missing when
+    a read-write mount is wanted. When <replaceable>dest</replaceable> is
+    missing <replaceable>dest</replaceable> will be identical to
+    <replaceable>src</replaceable>. An example for multiple mounts would be
+    <replaceable>-m
+    bind=/src1:/dest1:ro,bind=/src2:ro,overlay=/src3:/dest3</replaceable>.
+    </para>
+
+    <para>
+    The mounts, their options, and formats supported via the
+    <replaceable>-m</replaceable> flag are subject to change.
+    </para>
+  </refsect1>
+
+  <refsect1>
+
+    <title>Options</title>
+
+    <variablelist>
+
+         <varlistentry>
+           <term> <option>-N,--newname <replaceable>newname</replaceable></option> </term>
+          <listitem>
+           <para>The name for the copy.</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-p,--newpath <replaceable>newpath</replaceable></option> </term>
+          <listitem>
+           <para>The path for the copy.</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-R,--rename </option> </term>
+          <listitem>
+           <para>Rename the original container. </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-s,--snapshot </option> </term>
+          <listitem>
+            <para> Create a snapshot of the original container. The backing
+            storage for the copy must support snapshots. This currently includes
+            aufs, btrfs, lvm, overlay, and zfs. </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-F,--foreground</option> </term>
+          <listitem>
+            <para>Run the snapshot in the foreground. The snapshots console will
+            be attached to the current tty. (This option can only be specified
+            in conjunction with <replaceable>-e</replaceable>.)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-d, --daemon</option> </term>
+          <listitem>
+            <para> Run the snapshot as a daemon (This is the default mode for
+            ephemeral containers.). As the container has no more tty, if an
+            error occurs nothing will be displayed, the log file can
+            be used to check the error. (This option can only be specified in
+            conjunction with <replaceable>-e</replaceable>.)
+            </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-m, --mount <replaceable>mounttype</replaceable></option> </term>
+          <listitem>
+            <para>  Specify a mount for a snapshot  The
+            <replaceable>opts</replaceable> argument for the mount type can by
+            of type {aufs, bind, overlay}. For example <option>-m
+            bind=/src:/dest:ro,overlay=/src:/dest</option> (This option can
+            currently only be specified in conjunction with
+            <replaceable>-e</replaceable>.).</para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-B, --backingstorage <replaceable>backingstorage</replaceable></option></term>
+          <listitem>
+            <para>Specify the backing storage type to be used for the copy
+            where 'backingstorage' is of type 'aufs', 'btrfs', 'dir', 'lvm', 'loop',
+            'overlay', or 'zfs'. </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-L, --fssize <replaceable>size [unit]</replaceable></option></term>
+          <listitem>
+            <para>Specify the size for an 'lvm' filesystem. </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-D, --keepdata </option></term>
+          <listitem>
+            <para>When this option is specified with
+            <replaceable>-e</replaceable> a non-ephemeral container is created
+            and started. </para> </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-K, --keepname </option></term>
+          <listitem>
+            <para> When this option is specified the hostname of the original
+            container will be kept for the copy.</para> </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term> <option>-M, --keepmac </option></term>
+          <listitem>
+            <para> When this option is specified the MAC address of the original
+            container will be kept for the copy.</para> </listitem>
+         </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Copy hook</title>
+    <para>
+      If the container being copied has one or more
+      <filename>lxc.hook.clone</filename> specified, then the specified hooks
+      will be called for the new container. The first 3 arguments passed to the
+      clone hook will be the container name, a section ('lxc'), and the hook
+      type ('clone'). Extra arguments passed to <command>lxc-copy</command> will
+      be passed to the hook program starting at argument 4. The
+      <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
+      the path under which the container's root filesystem is mounted. The
+      configuration file pathname is stored in
+      <filename>LXC_CONFIG_FILE</filename>, the new container name in
+      <filename>LXC_NAME</filename>, the old container name in
+      <filename>LXC_SRC_NAME</filename>, and the path or device on which the
+      rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
+    </para>
+  </refsect1>
+
+  &commonoptions;
+
+  &seealso;
+
+  <refsect1>
+    <title>Author</title>
+    <para>Christian Brauner <email>christian.brauner@mailbox.org</email></para>
+  </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
index 3339bf3..1e97c40 100644 (file)
@@ -92,7 +92,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-f <replaceable>config_file</replaceable></option>
+         <option>-f, --config <replaceable>config_file</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -104,7 +104,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-t <replaceable>template</replaceable></option>
+         <option>-t, --template <replaceable>template</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -122,11 +122,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-B <replaceable>backingstore</replaceable></option>
+         <option>-B, --bdev <replaceable>backingstore</replaceable></option>
        </term>
        <listitem>
          <para>
-           'backingstore' is one of 'dir', 'lvm', 'loop', 'btrfs', 'zfs', or 'best'.  The
+           'backingstore' is one of 'dir', 'lvm', 'loop', 'btrfs', 'zfs', 'rbd', or 'best'.  The
            default is 'dir', meaning that the container root filesystem
            will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
            This backing store type allows the optional
@@ -158,6 +158,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
            If backingstore is 'loop', you can use <replaceable>--fstype FSTYPE</replaceable> and <replaceable>--fssize SIZE</replaceable> as 'lvm'. The default values for these options are the same as 'lvm'.
          </para>
          <para>
+           If backingstore is 'rbd', then you will need to have a valid configuration in <filename>ceph.conf</filename> and a <filename>ceph.client.admin.keyring</filename> defined.
+           You can specify the following options :
+           <replaceable>--rbdname RBDNAME</replaceable> will create a blockdevice named RBDNAME rather than the default, which is the container name.
+           <replaceable>--rbdpool POOL</replaceable> will create the blockdevice in the pool named POOL, rather than the default, which is 'lxc'.
+         </para>
+         <para>
            If backingstore is 'best', then lxc will try, in order, btrfs,
            zfs, lvm, and finally a directory backing store.
          </para>
index 435df3e..f1969de 100644 (file)
@@ -51,6 +51,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <command>lxc-destroy</command>
       <arg choice="req">-n <replaceable>name</replaceable></arg>
       <arg choice="opt">-f</arg>
+      <arg choice="opt">-s</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -81,6 +82,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
          </para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>-s, --snapshots</option></term>
+        <listitem>
+          <para>
+            destroy the specified container including all its snapshots.
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
 
   </refsect1>
index c90d374..8e17bbf 100644 (file)
@@ -67,7 +67,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <variablelist>
       <varlistentry>
         <term>
-          <option><optional>-h</optional></option>
+          <option>-h</option>
         </term>
         <listitem>
           <para>
@@ -77,9 +77,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
 
       <varlistentry>
-        <term>
-          <option>-n</option>
-        </term>
+        <term><option>-n, --name=<replaceable>NAME</replaceable></option></term>
         <listitem>
           <para>
              The name of the target container.
index 5707975..8ff1377 100644 (file)
@@ -71,19 +71,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-c <replaceable>KEY</replaceable></optional></option>
+          <option>-c, --config <replaceable>KEY</replaceable></option>
         </term>
         <listitem>
           <para>
             Print a configuration key from the container. This option
-            may be given mulitple times to print out multiple key = value pairs.
+            may be given multiple times to print out multiple key = value pairs.
           </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term>
-          <option><optional>-s</optional></option>
+          <option>-s, --state</option>
         </term>
         <listitem>
           <para>
@@ -94,7 +94,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-p</optional></option>
+          <option>-p, --pid</option>
         </term>
         <listitem>
           <para>
@@ -105,7 +105,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-i</optional></option>
+          <option>-i, --ips</option>
         </term>
         <listitem>
           <para>
@@ -116,7 +116,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-S</optional></option>
+          <option>-S, --stats</option>
         </term>
         <listitem>
           <para>
@@ -139,7 +139,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-H</optional></option>
+          <option>-H, --no-humanize</option>
         </term>
         <listitem>
           <para>
index 63826e1..d2850f2 100644 (file)
@@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 <!DOCTYPE refentry PUBLIC @docdtd@ [
 
+<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
 <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
 ]>
 
@@ -50,7 +51,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <cmdsynopsis>
       <command>lxc-ls</command>
       <arg choice="opt">-1</arg>
-      <arg choice="opt">-P <replaceable>lxcpath</replaceable></arg>
       <arg choice="opt">--active</arg>
       <arg choice="opt">--frozen</arg>
       <arg choice="opt">--running</arg>
@@ -58,9 +58,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <arg choice="opt">-f</arg>
       <arg choice="opt">-F <replaceable>format</replaceable></arg>
       <arg choice="opt">-g <replaceable>groups</replaceable></arg>
-      <arg choice="opt">--nesting</arg>
-      <arg choice="opt">filter</arg>
-      <arg choice="opt">--version</arg>
+      <arg choice="opt">--nesting=<replaceable>NUM</replaceable></arg>
+      <arg choice="opt">--filter=<replaceable>regex</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -77,7 +76,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <variablelist>
       <varlistentry>
         <term>
-          <option><optional>-1</optional></option>
+          <option>-1</option>
         </term>
         <listitem>
           <para>
@@ -88,18 +87,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-P, --lxcpath</optional></option>
-        </term>
-        <listitem>
-          <para>
-            Use an alternate container path. The default is @LXCPATH@.
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>
-          <option><optional>--active</optional></option>
+          <option>--active</option>
         </term>
         <listitem>
           <para>
@@ -110,7 +98,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--frozen</optional></option>
+          <option>--frozen</option>
         </term>
         <listitem>
           <para>
@@ -121,7 +109,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--running</optional></option>
+          <option>--running</option>
         </term>
         <listitem>
           <para>
@@ -132,7 +120,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--stopped</optional></option>
+          <option>--stopped</option>
         </term>
         <listitem>
           <para>
@@ -143,7 +131,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-f, --fancy</optional></option>
+          <option>-f,--fancy</option>
         </term>
         <listitem>
           <para>
@@ -154,7 +142,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-F, --fancy-format <replaceable>format</replaceable></optional></option>
+          <option>-F,--fancy-format <replaceable>format</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -166,7 +154,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-g, --groups <replaceable>groups</replaceable></optional></option>
+          <option>-g,--groups <replaceable>groups</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -178,34 +166,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--nesting</optional></option>
+          <option>--nesting=<replaceable>NUM</replaceable></option>
         </term>
         <listitem>
           <para>
-            Show nested containers.
+            Show nested containers. The number of nesting levels to be shown can
+            be specified by passing a number as argument.
           </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term>
-          <option><optional>filter</optional></option>
+          <option>--filter=<replaceable>regex</replaceable></option>
         </term>
         <listitem>
           <para>
-            The filter passed to <command>lxc-ls</command> will be
-            applied to the container name. The format is a regular expression.
-          </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term>
-          <option><optional>--version</optional></option>
-        </term>
-        <listitem>
-          <para>
-            Show the version number.
+            The regular expression passed to <command>lxc-ls</command> will be
+            applied to the container name. The format is a POSIX extended
+            regular expression. It can also be given as additional argument
+            without explicitly using <option>--filter</option>.
           </para>
         </listitem>
       </varlistentry>
@@ -236,12 +216,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     </variablelist>
   </refsect1>
 
+  &commonoptions;
+
   &seealso;
 
   <refsect1>
+    <title>History</title>
+    Written originally as a shell script by Daniel Lezcano and Serge Hallyn.
+    Later reimplemented and extended in Python by Stéphane Graber and then
+    reimplemented and extended in C by Christian Brauner.
+  </refsect1>
+
+  <refsect1>
     <title>Author</title>
-    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
+    <para>Christian Brauner <email>christian.brauner@mailbox.org</email>,
+    Stéphane Graber <email>stgraber@ubuntu.com</email></para>
   </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
index 5c7ea53..2986a3b 100644 (file)
@@ -67,7 +67,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <command>lxc-snapshot</command>
       <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
       <arg choice="req">-r, -restore <replaceable>snapshot-name</replaceable></arg>
-      <arg choice="opt"> <replaceable> newname</replaceable></arg>
+      <arg choice="opt">-N, --newname <replaceable> newname</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -127,9 +127,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
          </varlistentry>
 
          <varlistentry>
-           <term> <option>newname</option> </term>
+           <term> <option>-N, --newname</option> </term>
           <listitem>
-           <para> When restoring a snapshot, the last optional argument is the name to use for the restored container.  If no name is given, then the original container will be destroyed and the restored container will take its place.  Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots.</para>
+            <para> When restoring a snapshot, the last optional argument if not given explicitly via <command>--newname</command> is the name to use for the restored container.  If the newname is identical to the original name of the container, then the original container will be destroyed and the restored container will take its place. Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots.</para>
           </listitem>
          </varlistentry>
 
index 6f3a325..6831578 100644 (file)
@@ -73,7 +73,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <variablelist>
       <varlistentry>
         <term>
-          <option>-o</option>
+          <option>-o, --orig <replaceable>orig</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -84,7 +84,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-n</optional></option>
+          <option>-n, --name <replaceable>name</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -95,7 +95,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-d</optional></option>
+          <option>-d, --daemon</option>
         </term>
         <listitem>
           <para>
@@ -107,7 +107,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--bdir</optional></option>
+          <option>-b, --bdir <replaceable>bdir</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -119,7 +119,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--user</optional></option>
+          <option>-u, --user <replaceable>user</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -131,7 +131,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--key</optional></option>
+          <option>-S, --key <replaceable>key</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -142,7 +142,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--storage-type</optional></option>
+          <option>-s, --storage-type <replaceable>storage type</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -153,7 +153,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--union-type</optional></option>
+          <option>-U, --union-type <replaceable>union type</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -165,7 +165,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>--keep-data</optional></option>
+          <option>-k, --keep-data</option>
         </term>
         <listitem>
           <para>
@@ -178,7 +178,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>COMMAND</optional></option>
+          <option>COMMAND</option>
         </term>
         <listitem>
           <para>
@@ -227,6 +227,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>Notes</title>
+    <para>
+    <command>lxc-start-ephemeral</command> is deprecated in favor of
+    <command>lxc-copy</command>.
+    </para>
+  </refsect1>
+
   &seealso;
 
   <refsect1>
index bc5e6a8..3c69fed 100644 (file)
@@ -70,7 +70,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       the container's init process, waiting up to 60 seconds for the container
       to exit, and then returning. If the container fails to cleanly exit in
       60 seconds, it will be sent the <command>lxc.stopsignal</command>
-      (defaults to SIGKILL) to force it to shut down.
+      (defaults to SIGKILL) to force it to shut down. A request to reboot will
+      send the <command>lxc.rebootsignal</command> (defaults to SIGINT) to the
+      container's init process.
     </para>
        <para>
        The <optional>-W</optional>, <optional>-r</optional>,
index 2e2f774..38aa951 100644 (file)
@@ -72,7 +72,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
         <term>
-          <option><optional>-d, --delay <replaceable>delay</replaceable></optional></option>
+          <option>-d, --delay <replaceable>delay</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -83,7 +83,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
       <varlistentry>
         <term>
-          <option><optional>-s, --sort <replaceable>sortby</replaceable></optional></option>
+          <option>-s, --sort <replaceable>sortby</replaceable></option>
         </term>
         <listitem>
           <para>
@@ -96,7 +96,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
       <varlistentry>
         <term>
-          <option><optional>-r, --reverse</optional></option>
+          <option>-r, --reverse</option>
         </term>
         <listitem>
           <para>
index 678ae9e..16fb1dc 100644 (file)
@@ -93,7 +93,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
            <replaceable>NETWORK</replaceable>. This allows one to change
            the context of the process to e.g. the network namespace of the
            container while retaining the other namespaces as those of the
-           host.
+           host. (The pipe symbol needs to be escaped, e.g.
+            <replaceable>MOUNT\|PID</replaceable> or quoted, e.g.
+            <replaceable>"MOUNT|PID"</replaceable>.)
          </para>
        </listitem>
       </varlistentry>
index 8565238..dfc7b45 100644 (file)
@@ -63,6 +63,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <para>
       <command>user</command> <command>type</command> <command>bridge</command> <command>number</command>
       </para>
+      <para>or</para>
+      <para>
+      <command>@group</command> <command>type</command> <command>bridge</command> <command>number</command>
+      </para>
       <para>
       Where
       </para>
@@ -82,6 +86,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
        <varlistentry>
          <term>
+           <option>@group</option>
+         </term>
+         <listitem>
+           <para>
+             is the groupname to which this entry applies.
+           </para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term>
            <option>type</option>
          </term>
          <listitem>
@@ -110,12 +125,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
          </term>
          <listitem>
            <para>
-             is the number of network interfaces of the given type which the
-             given user may attach to the given bridge, for instance <filename>2</filename>.
+             is the number or quota of network interfaces of the given type which the
+             given user or group may attach to the given bridge, for instance <filename>2</filename>.
             </para>
          </listitem>
        </varlistentry>
       </variablelist>
+
+      <para>
+        Since a user can be specified both by username as well as one or
+        more usergroups, it is possible that several configuration lines
+        enable that user to create network interfaces. In such cases, any
+        interfaces create are counted towards the quotas of the user or group
+        in the order in which they appear in the file. If the quota of one
+        line is full, the rest will be parsed until one is found or the end of
+        the file.
+      </para>
     </refsect2>
 
   </refsect1>
index 5c5c958..c32f8a5 100644 (file)
@@ -69,7 +69,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-s <replaceable>states</replaceable></option>
+         <option>-s, --state <replaceable>states</replaceable></option>
        </term>
        <listitem>
          <para>
@@ -81,7 +81,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
       <varlistentry>
        <term>
-         <option>-t <replaceable>timeout</replaceable></option>
+         <option>-t, --timeout <replaceable>timeout</replaceable></option>
        </term>
        <listitem>
          <para>
index 8b57e05..05baddd 100644 (file)
@@ -72,7 +72,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <para>
       Each option in the configuration file has the form <command>key
       = value</command> fitting in one line. The '#' character means
-      the line is a comment.
+      the line is a comment. List options, like capabilities and cgroups
+      options, can be used with no value to clear any previously
+      defined values of that option.
     </para>
 
     <refsect2>
@@ -158,46 +160,68 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     <refsect2>
       <title>Halt signal</title>
       <para>
-    Allows one to specify signal name or number, sent by lxc-stop to the
-    container's init process to cleanly shutdown the container. Different
-    init systems could use different signals to perform clean shutdown
-    sequence. This option allows the signal to be specified in kill(1)
-    fashion, e.g. SIGPWR, SIGRTMIN+14, SIGRTMAX-10 or plain number. The
-    default signal is SIGPWR.
+        Allows one to specify signal name or number, sent by lxc-stop to the
+        container's init process to cleanly shutdown the container. Different
+        init systems could use different signals to perform clean shutdown
+        sequence. This option allows the signal to be specified in kill(1)
+        fashion, e.g. SIGPWR, SIGRTMIN+14, SIGRTMAX-10 or plain number. The
+        default signal is SIGPWR.
       </para>
       <variablelist>
-    <varlistentry>
-      <term>
-        <option>lxc.haltsignal</option>
-      </term>
-      <listitem>
-        <para>
-          specify the signal used to halt the container
-        </para>
-      </listitem>
-    </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.haltsignal</option>
+          </term>
+          <listitem>
+            <para>
+              specify the signal used to halt the container
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Reboot signal</title>
+      <para>
+        Allows one to specify signal name or number, sent by lxc-stop to
+        reboot the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGTERM, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGINT.
+          </para>
+          <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.rebootsignal</option>
+          </term>
+          <listitem>
+            <para>
+              specify the signal used to reboot the container
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
     <refsect2>
       <title>Stop signal</title>
       <para>
-    Allows one to specify signal name or number, sent by lxc-stop to forcibly
-    shutdown the container. This option allows signal to be specified in
-    kill(1) fashion, e.g. SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
-    The default signal is SIGKILL.
-      </para>
-      <variablelist>
-    <varlistentry>
-      <term>
-        <option>lxc.stopsignal</option>
-      </term>
-      <listitem>
-        <para>
-          specify the signal used to stop the container
-        </para>
-      </listitem>
-    </varlistentry>
+        Allows one to specify signal name or number, sent by lxc-stop to forcibly
+        shutdown the container. This option allows signal to be specified in
+        kill(1) fashion, e.g. SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+        The default signal is SIGKILL.
+          </para>
+          <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.stopsignal</option>
+          </term>
+          <listitem>
+            <para>
+              specify the signal used to stop the container
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -211,16 +235,69 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
         Defaults to: /sbin/init
       </para>
       <variablelist>
-    <varlistentry>
-      <term>
-        <option>lxc.init_cmd</option>
-      </term>
-      <listitem>
-        <para>
-          Absolute path from container rootfs to the binary to use as init.
-        </para>
-      </listitem>
-    </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.init_cmd</option>
+          </term>
+          <listitem>
+            <para>
+              Absolute path from container rootfs to the binary to use as init.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Init ID</title>
+      <para>
+        Sets the UID/GID to use for the init system, and subsequent command, executed by lxc-execute.
+
+        These options are only used when lxc-execute is started in a private user namespace.
+
+        Defaults to: UID(0), GID(0)
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.init_uid</option>
+          </term>
+          <listitem>
+            <para>
+              UID to use within a private user namesapce for init.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.init_gid</option>
+          </term>
+          <listitem>
+            <para>
+              GID to use within a private user namesapce for init.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Ephemeral</title>
+      <para>
+        Allows one to specify whether a container will be destroyed on shutdown.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.ephemeral</option>
+          </term>
+          <listitem>
+            <para>
+              The only allowed values are 0 and 1. Set this to 1 to destroy a
+              container on shutdown. 
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -238,6 +315,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <variablelist>
         <varlistentry>
           <term>
+            <option>lxc.network</option>
+          </term>
+          <listitem>
+            <para>
+              may be used without a value to clear all previous network options.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
             <option>lxc.network.type</option>
           </term>
           <listitem>
@@ -303,16 +390,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
               <option>lxc.network.macvlan.mode</option> specifies the
               mode the macvlan will use to communicate between
               different macvlan on the same upper device. The accepted
-              modes are <option>private</option>, the device never
-              communicates with any other device on the same upper_dev (default),
-              <option>vepa</option>, the new Virtual Ethernet Port
+              modes are <option>private</option>, <option>vepa</option>,
+              <option>bridge</option> and <option>passthru</option>.
+             In <option>private</option> mode, the device never
+              communicates with any other device on the same upper_dev (default).
+              In <option>vepa</option> mode, the new Virtual Ethernet Port
               Aggregator (VEPA) mode, it assumes that the adjacent
               bridge returns all frames where both source and
               destination are local to the macvlan port, i.e. the
               bridge is set up as a reflective relay.  Broadcast
               frames coming in from the upper_dev get flooded to all
               macvlan interfaces in VEPA mode, local frames are not
-              delivered locally, or <option>bridge</option>, it
+              delivered locally. In <option>bridge</option> mode, it
               provides the behavior of a simple bridge between
               different macvlan interfaces on the same port. Frames
               from one interface to another one get delivered directly
@@ -321,7 +410,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
               interface, but when they come back from a reflective
               relay, we don't deliver them again.  Since we know all
               the MAC addresses, the macvlan bridge mode does not
-              require learning or STP like the bridge module does.
+              require learning or STP like the bridge module does. In
+              <option>passthru</option> mode, all frames received by
+              the physical interface are forwarded to the macvlan
+              interface. Only one macvlan interface in <option>passthru</option>
+              mode is possible for one physical interface.
             </para>
 
             <para>
@@ -650,7 +743,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
         <filename>/dev</filename> to be set up as needed in the container
         rootfs.  If lxc.autodev is set to 1, then after mounting the container's
         rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
-        (limited to 100k) and fill in a minimal set of initial devices.
+        (limited to 500k) and fill in a minimal set of initial devices.
         This is generally required when starting a container containing
         a "systemd" based "init" but may be optional at other times.  Additional
         devices in the containers /dev directory may be created through the
@@ -819,7 +912,7 @@ proc proc proc nodev,noexec,nosuid 0 0
                   the container's own cgroup into that directory.
                   The container will be able to write to its own
                   cgroup directory, but not the parents, since they
-                  will be remounted read-only
+                  will be remounted read-only.
                 </para>
               </listitem>
               <listitem>
@@ -894,6 +987,12 @@ proc proc proc nodev,noexec,nosuid 0 0
               </listitem>
             </itemizedlist>
             <para>
+             If cgroup namespaces are enabled, then any <option>cgroup</option>
+             auto-mounting request will be ignored, since the container can
+             mount the filesystems itself, and automounting can confuse the
+             container init.
+            </para>
+            <para>
               Note that if automatic mounting of the cgroup filesystem
               is enabled, the tmpfs under
               <filename>/sys/fs/cgroup</filename> will always be
@@ -955,7 +1054,9 @@ proc proc proc nodev,noexec,nosuid 0 0
           specifies that the rootfs should be an overlay with <filename>/upper</filename>
           being mounted read-write over a read-only mount of <filename>/lower</filename>.
           <filename>aufs:/lower:/upper</filename> does the same using aufs in place
-          of overlayfs. <filename>loop:/file</filename> tells lxc to attach
+          of overlayfs. For both <filename>overlayfs</filename> and
+          <filename>aufs</filename> multiple <filename>/lower</filename>
+          directories can be specified. <filename>loop:/file</filename> tells lxc to attach
           <filename>/file</filename> to a loop device and mount the loop device.
             </para>
           </listitem>
@@ -990,6 +1091,20 @@ proc proc proc nodev,noexec,nosuid 0 0
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>
+            <option>lxc.rootfs.backend</option>
+          </term>
+          <listitem>
+            <para>
+              specify the rootfs backend type to use, for instance 'dir' or
+             'zfs'.  While this can be guessed by lxc at container startup,
+             doing so takes time.  Specifying it here avoids extra
+             processing.
+            </para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
     </refsect2>
 
@@ -1045,7 +1160,9 @@ proc proc proc nodev,noexec,nosuid 0 0
               <citerefentry>
                 <refentrytitle><command>capabilities</command></refentrytitle>
                 <manvolnum>7</manvolnum>
-              </citerefentry>,
+              </citerefentry>.
+              If used with no value, lxc will clear any drop capabilities
+              specified up to this point.
             </para>
           </listitem>
         </varlistentry>
@@ -1072,7 +1189,9 @@ proc proc proc nodev,noexec,nosuid 0 0
         If lxc was compiled and installed with apparmor support, and the host
         system has apparmor enabled, then the apparmor profile under which the
         container should be run can be specified in the container
-        configuration.  The default is <command>lxc-container-default</command>.
+        configuration.  The default is <command>lxc-container-default-cgns</command>
+       if the host kernel is cgroup namespace aware, or
+       <command>lxc-container-default</command> othewise.
       </para>
       <variablelist>
         <varlistentry>
@@ -1086,6 +1205,11 @@ proc proc proc nodev,noexec,nosuid 0 0
               use
             </para>
               <programlisting>lxc.aa_profile = unconfined</programlisting>
+            <para>
+              If the apparmor profile should remain unchanged (i.e. if you
+             are nesting containers and are already confined), then use
+            </para>
+              <programlisting>lxc.aa_profile = unchanged</programlisting>
           </listitem>
         </varlistentry>
         <varlistentry>
@@ -1231,9 +1355,12 @@ mknod errno 0
           <listitem><para> Container name. </para></listitem>
           <listitem><para> Section (always 'lxc'). </para></listitem>
           <listitem><para> The hook type (i.e. 'clone' or 'pre-mount'). </para></listitem>
-          <listitem><para> Additional arguments In the
+          <listitem><para> Additional arguments. In the
           case of the clone hook, any extra arguments passed to
-          lxc-clone will appear as further arguments to the hook. </para></listitem>
+          lxc-clone will appear as further arguments to the hook.
+          In the case of the stop hook, paths to filedescriptors
+          for each of the container's namespaces along with their types
+          are passed. </para></listitem>
         </itemizedlist>
         The following environment variables are set:
         <itemizedlist>
@@ -1330,6 +1457,26 @@ mknod errno 0
       <variablelist>
         <varlistentry>
           <term>
+            <option>lxc.hook.stop</option>
+          </term>
+          <listitem>
+            <para>
+              A hook to be run in the host's namespace with references
+              to the container's namespaces after the container has been shut
+              down. For each namespace an extra argument is passed to the hook
+              containing the namespace's type and a filename that can be used to
+              obtain a file descriptor to the corresponding namespace, separated
+              by a colon. The type is the name as it would appear in the
+              <filename>/proc/PID/ns</filename> directory.
+              For instance for the mount namespace the argument usually looks
+              like <filename>mnt:/proc/PID/fd/12</filename>.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
             <option>lxc.hook.post-stop</option>
           </term>
           <listitem>
@@ -1354,6 +1501,18 @@ mknod errno 0
           </listitem>
         </varlistentry>
       </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.hook.destroy</option>
+          </term>
+          <listitem>
+            <para>
+              A hook to be run when the container is destroyed.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
     </refsect2>
 
     <refsect2>
@@ -1450,7 +1609,47 @@ mknod errno 0
           </listitem>
         </varlistentry>
       </variablelist>
-
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_SRC_NAME</option>
+          </term>
+          <listitem>
+            <para>
+              Only for the clone hook. Is set to the original container name.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_TARGET</option>
+          </term>
+          <listitem>
+            <para>
+              Only for the stop hook. Is set to "stop" for a container
+              shutdown or "reboot" for a container reboot.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>LXC_CGNS_AWARE</option>
+          </term>
+          <listitem>
+            <para>
+             If unset, then this version of lxc is not aware of cgroup
+             namespaces.  If set, it will be set to 1, and lxc is aware
+             of cgroup namespaces.  Note this does not guarantee that
+             cgroup namespaces are enabled in the kernel.  This is used
+             by the lxcfs mount hook.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
     </refsect2>
     <refsect2>
     <title>Logging</title>
@@ -1545,6 +1744,19 @@ mknod errno 0
         </varlistentry>
         <varlistentry>
           <term>
+            <option>lxc.monitor.unshare</option>
+          </term>
+          <listitem>
+            <para>
+              If not zero the mount namespace will be unshared from the host
+              before initializing the container (before running any pre-start
+              hooks). This requires the CAP_SYS_ADMIN capability at startup.
+              Default is 0.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>
             <option>lxc.group</option>
           </term>
           <listitem>
index c522e2b..1b98b47 100644 (file)
@@ -458,7 +458,7 @@ rootfs
 
       <para>
        Here is an example on how the combination of these commands
-       allow to list all the containers and retrieve their state.
+       allows one to list all the containers and retrieve their state.
        <programlisting>
          for i in $(lxc-ls -1); do
            lxc-info -n $i
index 7ad71aa..cb1f881 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,12 +89,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = doc/rootfs
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -138,6 +148,7 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(READMEdir)"
 DATA = $(README_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +201,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +215,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +307,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -319,7 +333,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/rootfs/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu doc/rootfs/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -512,6 +525,8 @@ uninstall-am: uninstall-READMEDATA
        pdf-am ps ps-am tags-am uninstall uninstall-READMEDATA \
        uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 4954e8e..3b3ecd7 100644 (file)
@@ -38,6 +38,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </citerefentry>,
 
       <citerefentry>
+       <refentrytitle><command>lxc-copy</command></refentrytitle>
+       <manvolnum>1</manvolnum>
+      </citerefentry>,
+
+      <citerefentry>
        <refentrytitle><command>lxc-destroy</command></refentrytitle>
        <manvolnum>1</manvolnum>
       </citerefentry>,
index be55601..23b85c8 100644 (file)
@@ -1,4 +1,5 @@
 hooksdir=@LXCHOOKDIR@
+binhooksdir=@LXCBINHOOKDIR@
 
 hooks_SCRIPTS = \
        clonehostname \
@@ -6,4 +7,15 @@ hooks_SCRIPTS = \
        ubuntu-cloud-prep \
        squid-deb-proxy-client
 
+binhooks_PROGRAMS = \
+       unmount-namespace
+
+unmount_namespace_SOURCES = \
+       unmount-namespace.c
+
+if IS_BIONIC
+unmount_namespace_SOURCES += \
+       ../src/include/lxcmntent.c ../src/include/lxcmntent.h
+endif
+
 EXTRA_DIST=$(hooks_SCRIPTS)
index 9f4ec62..1069ba2 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 
+
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,17 +89,31 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+binhooks_PROGRAMS = unmount-namespace$(EXEEXT)
+@IS_BIONIC_TRUE@am__append_1 = \
+@IS_BIONIC_TRUE@       ../src/include/lxcmntent.c ../src/include/lxcmntent.h
+
 subdir = hooks
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(binhooksdir)" "$(DESTDIR)$(hooksdir)"
+PROGRAMS = $(binhooks_PROGRAMS)
+am__unmount_namespace_SOURCES_DIST = unmount-namespace.c \
+       ../src/include/lxcmntent.c ../src/include/lxcmntent.h
+am__dirstamp = $(am__leading_dot)dirstamp
+@IS_BIONIC_TRUE@am__objects_1 = ../src/include/lxcmntent.$(OBJEXT)
+am_unmount_namespace_OBJECTS = unmount-namespace.$(OBJEXT) \
+       $(am__objects_1)
+unmount_namespace_OBJECTS = $(am_unmount_namespace_OBJECTS)
+unmount_namespace_LDADD = $(LDADD)
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -116,7 +141,6 @@ am__uninstall_files_from_dir = { \
     || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
-am__installdirs = "$(DESTDIR)$(hooksdir)"
 SCRIPTS = $(hooks_SCRIPTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -130,14 +154,49 @@ AM_V_at = $(am__v_at_@AM_V@)
 am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
 am__v_at_0 = @
 am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(unmount_namespace_SOURCES)
+DIST_SOURCES = $(am__unmount_namespace_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -190,6 +249,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -203,6 +263,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -294,6 +355,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -303,16 +365,19 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 hooksdir = @LXCHOOKDIR@
+binhooksdir = @LXCBINHOOKDIR@
 hooks_SCRIPTS = \
        clonehostname \
        mountecryptfsroot \
        ubuntu-cloud-prep \
        squid-deb-proxy-client
 
+unmount_namespace_SOURCES = unmount-namespace.c $(am__append_1)
 EXTRA_DIST = $(hooks_SCRIPTS)
 all: all-am
 
 .SUFFIXES:
+.SUFFIXES: .c .o .obj
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
@@ -325,7 +390,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu hooks/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu hooks/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -343,6 +407,60 @@ $(top_srcdir)/configure:  $(am__configure_deps)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
        cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
+install-binhooksPROGRAMS: $(binhooks_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       @list='$(binhooks_PROGRAMS)'; test -n "$(binhooksdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(binhooksdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(binhooksdir)" || exit 1; \
+       fi; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p \
+         ; then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' \
+           -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+             echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(binhooksdir)$$dir'"; \
+             $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(binhooksdir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-binhooksPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(binhooks_PROGRAMS)'; test -n "$(binhooksdir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' \
+       `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(binhooksdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(binhooksdir)" && rm -f $$files
+
+clean-binhooksPROGRAMS:
+       -test -z "$(binhooks_PROGRAMS)" || rm -f $(binhooks_PROGRAMS)
+../src/include/$(am__dirstamp):
+       @$(MKDIR_P) ../src/include
+       @: > ../src/include/$(am__dirstamp)
+../src/include/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) ../src/include/$(DEPDIR)
+       @: > ../src/include/$(DEPDIR)/$(am__dirstamp)
+../src/include/lxcmntent.$(OBJEXT): ../src/include/$(am__dirstamp) \
+       ../src/include/$(DEPDIR)/$(am__dirstamp)
+
+unmount-namespace$(EXEEXT): $(unmount_namespace_OBJECTS) $(unmount_namespace_DEPENDENCIES) $(EXTRA_unmount_namespace_DEPENDENCIES) 
+       @rm -f unmount-namespace$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unmount_namespace_OBJECTS) $(unmount_namespace_LDADD) $(LIBS)
 install-hooksSCRIPTS: $(hooks_SCRIPTS)
        @$(NORMAL_INSTALL)
        @list='$(hooks_SCRIPTS)'; test -n "$(hooksdir)" || list=; \
@@ -378,12 +496,84 @@ uninstall-hooksSCRIPTS:
        files=`for p in $$list; do echo "$$p"; done | \
               sed -e 's,.*/,,;$(transform)'`; \
        dir='$(DESTDIR)$(hooksdir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
 
-ctags CTAGS:
-
-cscope cscopelist:
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+       -rm -f ../src/include/*.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@../src/include/$(DEPDIR)/lxcmntent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unmount-namespace.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       $(am__define_uniq_tagged_files); \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       $(am__define_uniq_tagged_files); \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+       list='$(am__tagged_files)'; \
+       case "$(srcdir)" in \
+         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+         *) sdir=$(subdir)/$(srcdir) ;; \
+       esac; \
+       for i in $$list; do \
+         if test -f "$$i"; then \
+           echo "$(subdir)/$$i"; \
+         else \
+           echo "$$sdir/$$i"; \
+         fi; \
+       done >> $(top_builddir)/cscope.files
 
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
        @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -417,9 +607,9 @@ distdir: $(DISTFILES)
        done
 check-am: all-am
 check: check-am
-all-am: Makefile $(SCRIPTS)
+all-am: Makefile $(PROGRAMS) $(SCRIPTS)
 installdirs:
-       for dir in "$(DESTDIR)$(hooksdir)"; do \
+       for dir in "$(DESTDIR)$(binhooksdir)" "$(DESTDIR)$(hooksdir)"; do \
          test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
 install: install-am
@@ -448,17 +638,21 @@ clean-generic:
 distclean-generic:
        -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
        -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+       -rm -f ../src/include/$(DEPDIR)/$(am__dirstamp)
+       -rm -f ../src/include/$(am__dirstamp)
 
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
 clean: clean-am
 
-clean-am: clean-generic mostlyclean-am
+clean-am: clean-binhooksPROGRAMS clean-generic mostlyclean-am
 
 distclean: distclean-am
+       -rm -rf ../src/include/$(DEPDIR) ./$(DEPDIR)
        -rm -f Makefile
-distclean-am: clean-am distclean-generic
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
 
 dvi: dvi-am
 
@@ -472,7 +666,7 @@ info: info-am
 
 info-am:
 
-install-data-am: install-hooksSCRIPTS
+install-data-am: install-binhooksPROGRAMS install-hooksSCRIPTS
 
 install-dvi: install-dvi-am
 
@@ -501,12 +695,13 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
+       -rm -rf ../src/include/$(DEPDIR) ./$(DEPDIR)
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
 mostlyclean: mostlyclean-am
 
-mostlyclean-am: mostlyclean-generic
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
 
 pdf: pdf-am
 
@@ -516,21 +711,26 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-hooksSCRIPTS
+uninstall-am: uninstall-binhooksPROGRAMS uninstall-hooksSCRIPTS
 
 .MAKE: install-am install-strip
 
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
-       ctags-am distclean distclean-generic distdir dvi dvi-am html \
-       html-am info info-am install install-am install-data \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+       clean-binhooksPROGRAMS clean-generic cscopelist-am ctags \
+       ctags-am distclean distclean-compile distclean-generic \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-binhooksPROGRAMS install-data \
        install-data-am install-dvi install-dvi-am install-exec \
        install-exec-am install-hooksSCRIPTS install-html \
        install-html-am install-info install-info-am install-man \
        install-pdf install-pdf-am install-ps install-ps-am \
        install-strip installcheck installcheck-am installdirs \
        maintainer-clean maintainer-clean-generic mostlyclean \
-       mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \
-       uninstall-am uninstall-hooksSCRIPTS
+       mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+       tags tags-am uninstall uninstall-am uninstall-binhooksPROGRAMS \
+       uninstall-hooksSCRIPTS
+
+.PRECIOUS: Makefile
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
index b3cf232..b89e79f 100755 (executable)
@@ -31,13 +31,14 @@ Usage: ${0##*/} [options] root-dir
   [ -L | --nolocales ]:    Do not copy host's locales into container
   [ -S | --auth-key ]:     ssh public key file for datasource [ds]
   [ -u | --userdata ]:     user-data file for cloud-init [ds]
+  [ -V | --vendordata ]:   vendor-data file for cloud-init [ds]
 
 EOF
 }
 
 prep() {
     local short_opts="Chi:L:S:u:v"
-    local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,create-etc-init,userdata:,verbose"
+    local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,create-etc-init,userdata:,vendordata:,verbose"
     local getopt_out getopt_ret
     getopt_out=$(getopt --name "${0##*/}" \
         --options "${short_opts}" --long "${long_opts}" -- "$@" 2>/dev/null) ||
@@ -49,7 +50,7 @@ prep() {
     fi
 
     local cur="" next=""
-    local userdata="" hostid="" authkey="" locales=1 cloud=0
+    local vendordata="" userdata="" hostid="" authkey="" locales=1 cloud=0
     local create_etc_init=0 name="ubuntucloud-lxc"
 
     while [ $# -ne 0 ]; do
@@ -65,6 +66,10 @@ prep() {
                 [ -f "$next" ] ||
                     { error "--auth-key: '$next' not a file"; return 1; }
                 authkey="$next";;
+            -V|--vendordata)
+                [ -f "$next" ] ||
+                    { error "--vendordata: '$next' not a file"; return 1; }
+                vendordata="$next";;
             -u|--userdata)
                 [ -f "$next" ] ||
                     { error "--userdata: '$next' not a file"; return 1; }
@@ -156,6 +161,13 @@ prep() {
             error "failed to write user-data write to '$seed_d/user-data'";
             return 1;
         }
+
+        if [ -n "$vendordata" ]; then
+            cp "$vendordata" "$seed_d/vendor-data" || {
+                error "failed copy vendordata to $seed_d/vendor-data";
+                return 1;
+            }
+        fi
     fi
 
 }
diff --git a/hooks/unmount-namespace.c b/hooks/unmount-namespace.c
new file mode 100644 (file)
index 0000000..99b2844
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright © 2015 Wolfgang Bumiller <w.bumiller@proxmox.com>.
+ * Copyright © 2015 Proxmox Server Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * --
+ *
+ * This stop-hook unmounts everything in the container's namespace, and thereby
+ * waits for all calls commands to finish. This is useful when one needs to be
+ * sure that network filesystems are finished unmounting in the namespace
+ * before continuing with other tasks. Without this hook the cleanup of mounts
+ * is done by the kernel in the background after all the references to the
+ * namespaces are gone.
+ */
+
+#define _GNU_SOURCE    /* setns */
+#include <stdio.h>     /* fdopen, getmntent, endmntent */
+#include <stdlib.h>    /* malloc, qsort */
+#include <unistd.h>    /* close */
+#include <string.h>    /* strcmp, strncmp, strdup, strerror */
+#include <sched.h>     /* setns */
+#include <sys/mount.h> /* umount2 */
+#include <sys/types.h> /* openat, open */
+#include <sys/stat.h>  /* openat, open */
+#include <fcntl.h>     /* openat, open */
+#include <errno.h>     /* errno */
+
+#include <../src/config.h>
+
+#if IS_BIONIC
+#include <../src/include/lxcmntent.h>
+#else
+#include <mntent.h>
+#endif
+
+#ifndef O_PATH
+#define O_PATH      010000000
+#endif
+
+/* Define setns() if missing from the C library */
+#ifndef HAVE_SETNS
+static inline int setns(int fd, int nstype)
+{
+#ifdef __NR_setns
+       return syscall(__NR_setns, fd, nstype);
+#elif defined(__NR_set_ns)
+       return syscall(__NR_set_ns, fd, nstype);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+#endif
+
+struct mount {
+       char *src; /* currently not used */
+       char *dst;
+       char *fs; /* currently not used */
+};
+
+static void mount_free(struct mount *mnt) {
+       free(mnt->src);
+       free(mnt->dst);
+       free(mnt->fs);
+}
+
+static int mount_cmp_dst(const void *a_, const void *b_) {
+       struct mount *a = (struct mount*)a_;
+       struct mount *b = (struct mount*)b_;
+       return strcmp(b->dst, a->dst); /* swapped order */
+}
+
+/* Unmounting /dev/pts fails, and  so /dev also fails, but /dev is not what
+ * we're interested in. (There might also still be /dev/cgroup mounts).
+ */
+static int mount_should_error(const struct mount *mnt) {
+       const char *dst = mnt->dst;
+       return !(strncmp(dst, "/dev", 4) == 0 && (dst[4] == 0 || dst[4] == '/'));
+}
+
+/* Read mounts from 'self/mounts' relative to a directory filedescriptor.
+ * Before entering the container we open a handle to /proc on the host as we
+ * need to access /proc/self/mounts and the container's /proc doesn't contain
+ * our /self. We then use openat(2) to avoid having to mount a temporary /proc.
+ */
+static int read_mounts(int procfd, struct mount **mp, size_t *countp) {
+       int fd;
+       struct mntent *ent;
+       FILE *mf;
+       size_t capacity = 32;
+       size_t count = 0;
+       struct mount *mounts = (struct mount*)malloc(capacity * sizeof(*mounts));
+
+       if (!mounts) {
+               errno = ENOMEM;
+               return 0;
+       }
+
+       *mp = NULL;
+       *countp = 0;
+
+       fd = openat(procfd, "self/mounts", O_RDONLY);
+       if (fd < 0) {
+               free(mounts);
+               return 0;
+       }
+
+       mf = fdopen(fd, "r");
+       if (!mf) {
+               int error = errno;
+               close(fd);
+               errno = error;
+               free(mounts);
+               return 0;
+       }
+       while ((ent = getmntent(mf))) {
+               struct mount *new;
+               if (count == capacity) {
+                       capacity *= 2;
+                       new = (struct mount*)realloc(mounts, capacity * sizeof(*mounts));
+                       if (!new)
+                               goto out_alloc_entry;
+                       mounts = new;
+               }
+               new = &mounts[count++];
+               new->src = strdup(ent->mnt_fsname);
+               new->dst = strdup(ent->mnt_dir);
+               new->fs  = strdup(ent->mnt_type);
+               if (!new->src || !new->dst || !new->fs)
+                       goto out_alloc_entry;
+       }
+       endmntent(mf);
+
+       *mp = mounts;
+       *countp = count;
+
+       return 1;
+
+out_alloc_entry:
+       endmntent(mf);
+       while (count--) {
+               free(mounts[count].src);
+               free(mounts[count].dst);
+               free(mounts[count].fs);
+       }
+       free(mounts);
+       errno = ENOMEM;
+       return 0;
+}
+
+int main(int argc, char **argv) {
+       int i, procfd, ctmntfd;
+       struct mount *mounts;
+       size_t zi, count = 0;
+       const char *mntns = NULL;
+
+       if (argc < 4 || strcmp(argv[2], "lxc") != 0) {
+               fprintf(stderr, "%s: usage error, expected LXC hook arguments\n", argv[0]);
+               return 2;
+       }
+
+       if (strcmp(argv[3], "stop") != 0)
+               return 0;
+
+       for (i = 4; i != argc; ++i) {
+               if (!strncmp(argv[i], "mnt:", 4)) {
+                       mntns = argv[i] + 4;
+                       break;
+               }
+       }
+
+       if (!mntns) {
+               fprintf(stderr, "%s: no mount namespace provided\n", argv[0]);
+               return 3;
+       }
+
+       /* Open a handle to /proc on the host as we need to access /proc/self/mounts
+        * and the container's /proc doesn't contain our /self. See read_mounts().
+        */
+       procfd = open("/proc", O_RDONLY | O_DIRECTORY | O_PATH);
+       if (procfd < 0) {
+               fprintf(stderr, "%s: failed to open /proc: %s\n", argv[0], strerror(errno));
+               return 4;
+       }
+
+       /* Open the mount namespace and enter it. */
+       ctmntfd = open(mntns, O_RDONLY);
+       if (ctmntfd < 0) {
+               fprintf(stderr, "%s: failed to open mount namespace: %s\n",
+                       argv[0], strerror(errno));
+               close(procfd);
+               return 5;
+       }
+
+       if (setns(ctmntfd, CLONE_NEWNS) != 0) {
+               fprintf(stderr, "%s: failed to attach to namespace: %s\n",
+                       argv[0], strerror(errno));
+               close(ctmntfd);
+               close(procfd);
+               return 6;
+       }
+       close(ctmntfd);
+
+       /* Now read [[procfd]]/self/mounts */
+       if (!read_mounts(procfd, &mounts, &count)) {
+               fprintf(stderr, "%s: failed to read mountpoints: %s\n",
+                       argv[0], strerror(errno));
+               close(procfd);
+               return 7;
+       }
+       close(procfd);
+
+       /* Just sort to get a sane unmount-order... */
+       qsort(mounts, count, sizeof(*mounts), &mount_cmp_dst);
+
+       for (zi = 0; zi != count; ++zi) {
+               /* fprintf(stderr, "Unmount: %s\n", mounts[zi].dst); */
+               if (umount2(mounts[zi].dst, 0) != 0) {
+                       int error = errno;
+                       if (mount_should_error(&mounts[zi])) {
+                               fprintf(stderr, "%s: failed to unmount %s: %s\n",
+                                       argv[0], mounts[zi].dst, strerror(error));
+                       }
+               }
+               mount_free(&mounts[zi]);
+       }
+       free(mounts);
+
+       return 0;
+}
index af02adf..04bb223 100644 (file)
--- a/lxc.spec
+++ b/lxc.spec
@@ -60,7 +60,7 @@ BuildRequires: systemd
 %endif
 
 Name: lxc
-Version: 1.1.5
+Version: 2.0.0
 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
@@ -169,7 +169,7 @@ fi
 
 %post
 # This test should trigger a network configure on a new install.
-if [ ! -f %{_sysconfdir}/sysconfig/lxc-net ] || ! grep -q 'USE_LXC_BRIDGE=' %{_sysconfdir}/sysconfig/lxc-net
+if [ ! -f /usr/local/etc/default/lxc-net ] || ! grep -q 'USE_LXC_BRIDGE=' /usr/local/etc/default/lxc-net
 then
        # Grab a random 10net subnet.  Need to add test logic...
        while [ true ]
@@ -181,7 +181,7 @@ then
                fi
        done
 
-       cat >  %{_sysconfdir}/sysconfig/lxc-net <<EOF
+       cat >  /usr/local/etc/default/lxc-net <<EOF
 # Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
 # containers.  Set to "false" if you'll use virbr0 or another existing
 # bridge, or mavlan to your host's NIC.
@@ -244,6 +244,9 @@ fi
 %{_mandir}/ja/man1/lxc*
 %{_mandir}/ja/man5/lxc*
 %{_mandir}/ja/man7/lxc*
+%{_mandir}/ko/man1/lxc*
+%{_mandir}/ko/man5/lxc*
+%{_mandir}/ko/man7/lxc*
 %endif
 %{_datadir}/doc/*
 %{_datadir}/lxc/*
index a3cb6af..9cc8dc5 100644 (file)
@@ -169,7 +169,7 @@ fi
 
 %post
 # This test should trigger a network configure on a new install.
-if [ ! -f %{_sysconfdir}/sysconfig/lxc-net ] || ! grep -q 'USE_LXC_BRIDGE=' %{_sysconfdir}/sysconfig/lxc-net
+if [ ! -f @LXC_DISTRO_SYSCONF@/lxc-net ] || ! grep -q 'USE_LXC_BRIDGE=' @LXC_DISTRO_SYSCONF@/lxc-net
 then
        # Grab a random 10net subnet.  Need to add test logic...
        while [ true ]
@@ -181,7 +181,7 @@ then
                fi
        done
 
-       cat >  %{_sysconfdir}/sysconfig/lxc-net <<EOF
+       cat >  @LXC_DISTRO_SYSCONF@/lxc-net <<EOF
 # Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
 # containers.  Set to "false" if you'll use virbr0 or another existing
 # bridge, or mavlan to your host's NIC.
@@ -244,6 +244,9 @@ fi
 %{_mandir}/ja/man1/lxc*
 %{_mandir}/ja/man5/lxc*
 %{_mandir}/ja/man7/lxc*
+%{_mandir}/ko/man1/lxc*
+%{_mandir}/ko/man5/lxc*
+%{_mandir}/ko/man7/lxc*
 %endif
 %{_datadir}/doc/*
 %{_datadir}/lxc/*
index 29f3332..ef17226 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,13 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/config.h.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES =
@@ -145,6 +154,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -222,6 +232,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -235,6 +246,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -326,6 +338,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -351,7 +364,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu src/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -655,6 +667,8 @@ uninstall-am:
        mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
        tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index d49789d..169a758 100644 (file)
@@ -35,6 +35,9 @@
 /* Define to 1 if you have the `getline' function. */
 #undef HAVE_GETLINE
 
+/* Define to 1 if you have the `getsubopt' function. */
+#undef HAVE_GETSUBOPT
+
 /* Define to 1 if you have the `hasmntopt' function. */
 #undef HAVE_HASMNTOPT
 
diff --git a/src/include/getsubopt.c b/src/include/getsubopt.c
new file mode 100644 (file)
index 0000000..b75497b
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Android c-library does not have getsubopt,
+ * so code lifted from uClibc
+ * http://git.uclibc.org/uClibc/tree/libc/unistd/getsubopt.c
+ */
+
+/* Parse comma separate list into words.
+   Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+char *strchrnul(const char *s, int c)
+{
+    char *result;
+
+    result = strchr( s, c );
+
+    if( !result )
+    {
+        result = (char *)s + strlen( s );
+    }
+
+    return( result );
+}
+
+/* Parse comma separated suboption from *OPTIONP and match against
+   strings in TOKENS.  If found return index and set *VALUEP to
+   optional value introduced by an equal sign.  If the suboption is
+   not part of TOKENS return in *VALUEP beginning of unknown
+   suboption.  On exit *OPTIONP is set to the beginning of the next
+   token or at the terminating NUL character.  */
+int
+getsubopt (char **optionp, char *const *tokens, char **valuep)
+{
+  char *endp, *vstart;
+  int cnt;
+
+  if (**optionp == '\0')
+    return -1;
+
+  /* Find end of next token.  */
+  endp = strchrnul (*optionp, ',');
+
+  /* Find start of value.  */
+  vstart = memchr (*optionp, '=', endp - *optionp);
+  if (vstart == NULL)
+    vstart = endp;
+
+  /* Try to match the characters between *OPTIONP and VSTART against
+     one of the TOKENS.  */
+  for (cnt = 0; tokens[cnt] != NULL; ++cnt)
+    if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0
+    && tokens[cnt][vstart - *optionp] == '\0')
+      {
+    /* We found the current option in TOKENS.  */
+    *valuep = vstart != endp ? vstart + 1 : NULL;
+
+    if (*endp != '\0')
+      *endp++ = '\0';
+    *optionp = endp;
+
+    return cnt;
+      }
+
+  /* The current suboption does not match any option.  */
+  *valuep = *optionp;
+
+  if (*endp != '\0')
+    *endp++ = '\0';
+  *optionp = endp;
+
+  return -1;
+}
diff --git a/src/include/getsubopt.h b/src/include/getsubopt.h
new file mode 100644 (file)
index 0000000..b4e1622
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _getsubopt_h
+#define _getsubopt_h
+int getsubopt (char **optionp, char *const *tokens, char **valuep);
+#endif
index 109f322..1f954dd 100644 (file)
@@ -473,7 +473,9 @@ static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, stru
         {
             l_mask[i] = 0xff;
         }
-        l_mask[i] = 0xff << (8 - (l_prefix % 8));
+        if (l_prefix % 8) {
+            l_mask[i] = 0xff << (8 - (l_prefix % 8));
+        }
 
         makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
         l_entry->ifa_netmask = (struct sockaddr *)l_addr;
index 418322c..bf731a0 100644 (file)
@@ -21,8 +21,6 @@
 #ifndef _lxcmntent_h
 #define _lxcmntent_h
 
-#include <../config.h>
-
 #if IS_BIONIC
 struct mntent
 {
index 112e4f5..4a80369 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,13 +91,12 @@ build_triplet = @build@
 host_triplet = @host@
 @ENABLE_LUA_TRUE@so_PROGRAMS = core.so$(EXEEXT)
 subdir = src/lua-lxc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -186,6 +195,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -238,6 +248,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -251,6 +262,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -342,6 +354,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -384,7 +397,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lua-lxc/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu src/lua-lxc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -712,6 +724,8 @@ uninstall-am: uninstall-luaDATA uninstall-soPROGRAMS
        ps ps-am tags tags-am uninstall uninstall-am uninstall-luaDATA \
        uninstall-soPROGRAMS
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_LUA_TRUE@lxc.lua:
 
index 34180a7..3fb915b 100644 (file)
@@ -58,6 +58,9 @@
 
 #define CONTAINER_TYPENAME     "lxc.container"
 
+/* Max Lua arguments for function */
+#define MAXVARS        200
+
 static int container_new(lua_State *L)
 {
     struct lxc_container *c;
@@ -194,6 +197,20 @@ static int container_wait(lua_State *L)
     return 1;
 }
 
+static int container_rename(lua_State *L)
+{
+    struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
+    const char *new_name;
+    int argc = lua_gettop(L);
+
+    if (argc > 1) {
+       new_name = luaL_checkstring(L, 2);
+       lua_pushboolean(L, !!c->rename(c, new_name));
+    } else
+       lua_pushnil(L);
+    return 1;
+}
+
 static int container_freeze(lua_State *L)
 {
     struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
@@ -407,6 +424,73 @@ static int container_attach(lua_State *L)
     return 1;
 }
 
+static int container_get_interfaces(lua_State *L)
+{
+    struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
+    char **ifaces;
+    int i;
+
+    ifaces = c->get_interfaces(c);
+
+    if (!ifaces){
+       lua_pushnil(L);
+       return 1;
+    }
+
+    for (i = 0; ifaces[i]; i++);
+
+    /* protect LUA stack form overflow */
+    if (i > MAXVARS || !lua_checkstack(L, i)){
+        for (i = 0; ifaces[i]; i++)
+           free(ifaces[i]);
+       lua_pushnil(L);
+       return 1;
+    }
+    for (i = 0; ifaces[i]; i++){
+       lua_pushstring(L, ifaces[i]);
+       free(ifaces[i]);
+    }
+    return i;
+}
+
+static int container_get_ips(lua_State *L)
+{
+    struct lxc_container *c = lua_unboxpointer(L, 1, CONTAINER_TYPENAME);
+    int argc = lua_gettop(L);
+    char **addresses;
+    char *iface = NULL, *family = NULL;
+    int i, scope = 0;
+
+    if (argc > 1)
+       iface = (char *)luaL_checkstring(L, 2);
+    if (argc > 2)
+       family = (char *)luaL_checkstring(L, 3);
+    if (argc > 3)
+       scope = luaL_checkinteger(L, 4);
+
+    addresses = c->get_ips(c, iface, family, scope);
+
+    if (!addresses){
+       lua_pushnil(L);
+       return 1;
+    }
+
+    for (i = 0; addresses[i]; i++);
+
+    /* protect LUA stack form overflow */
+    if (i > MAXVARS || !lua_checkstack(L, i)){
+        for (i = 0; addresses[i]; i++)
+           free(addresses[i]);
+       lua_pushnil(L);
+       return 1;
+    }
+    for (i = 0; addresses[i]; i++){
+       lua_pushstring(L, addresses[i]);
+       free(addresses[i]);
+    }
+    return i;
+}
+
 static luaL_Reg lxc_container_methods[] =
 {
     {"attach",                  container_attach},
@@ -423,6 +507,7 @@ static luaL_Reg lxc_container_methods[] =
     {"stop",                   container_stop},
     {"shutdown",               container_shutdown},
     {"wait",                   container_wait},
+    {"rename",                 container_rename},
 
     {"config_file_name",       container_config_file_name},
     {"load_config",            container_load_config},
@@ -435,6 +520,8 @@ static luaL_Reg lxc_container_methods[] =
     {"set_config_item",                container_set_config_item},
     {"clear_config_item",      container_clear_config_item},
     {"get_keys",               container_get_keys},
+    {"get_interfaces",         container_get_interfaces},
+    {"get_ips",                        container_get_ips},
     {NULL, NULL}
 };
 
index 122a482..3d1de10 100755 (executable)
@@ -151,6 +151,11 @@ function container:destroy()
     return self.core:destroy()
 end
 
+-- return nil if name missing
+function container:rename(name)
+    return self.core:rename(name)
+end
+
 function container:get_config_path()
     return self.core:get_config_path()
 end
@@ -221,6 +226,16 @@ function container:get_keys(base)
     return ktab
 end
 
+-- return nil or more args
+function container:get_interfaces()
+    return self.core:get_interfaces()
+end
+
+-- return nil or more args
+function container:get_ips(...)
+    return self.core:get_ips(...)
+end
+
 function container:load_config(alt_path)
     if (alt_path) then
        return self.core:load_config(alt_path)
index ce46495..f361c3f 100644 (file)
@@ -6,7 +6,17 @@ pkginclude_HEADERS = \
 noinst_HEADERS = \
        arguments.h \
        attach.h \
-       bdev.h \
+       bdev/bdev.h \
+       bdev/lxcaufs.h \
+       bdev/lxcbtrfs.h \
+       bdev/lxcdir.h \
+       bdev/lxcloop.h \
+       bdev/lxclvm.h \
+       bdev/lxcnbd.h \
+       bdev/lxcoverlay.h \
+       bdev/lxcrbd.h \
+       bdev/lxcrsync.h \
+       bdev/lxczfs.h \
        caps.h \
        cgroup.h \
        conf.h \
@@ -16,7 +26,6 @@ noinst_HEADERS = \
        list.h \
        log.h \
        lxc.h \
-       lxc-btrfs.h \
        lxclock.h \
        monitor.h \
        namespace.h \
@@ -38,6 +47,10 @@ noinst_HEADERS += ../include/getline.h
 endif
 endif
 
+if !HAVE_GETSUBOPT
+noinst_HEADERS += ../include/getsubopt.h
+endif
+
 sodir=$(libdir)
 # use PROGRAMS to avoid complains from automake
 so_PROGRAMS = liblxc.so
@@ -56,7 +69,17 @@ endif
 
 liblxc_so_SOURCES = \
        arguments.c arguments.h \
-       bdev.c bdev.h lxc-btrfs.h \
+       bdev/bdev.c bdev/bdev.h \
+       bdev/lxcaufs.c bdev/lxcaufs.h \
+       bdev/lxcbtrfs.c bdev/lxcbtrfs.h \
+       bdev/lxcdir.c bdev/lxcdir.h \
+       bdev/lxcloop.c bdev/lxcloop.h \
+       bdev/lxclvm.c bdev/lxclvm.h \
+       bdev/lxcnbd.c bdev/lxcnbd.h \
+       bdev/lxcoverlay.c bdev/lxcoverlay.h \
+       bdev/lxcrbd.c bdev/lxcrbd.h \
+       bdev/lxcrsync.c bdev/lxcrsync.h \
+       bdev/lxczfs.c bdev/lxczfs.h \
        commands.c commands.h \
        start.c start.h \
        execute.c \
@@ -66,6 +89,7 @@ liblxc_so_SOURCES = \
        error.h error.c \
        parse.c parse.h \
        cgfs.c \
+       cgfsng.c \
        cgroup.c cgroup.h \
        lxc.h \
        initutils.c initutils.h \
@@ -121,6 +145,7 @@ AM_CFLAGS=-I$(top_srcdir)/src \
        -DLXCINITDIR=\"$(LXCINITDIR)\" \
        -DLIBEXECDIR=\"$(LIBEXECDIR)\" \
        -DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
+       -DLXCTEMPLATECONFIG=\"$(LXCTEMPLATECONFIG)\" \
        -DLOGPATH=\"$(LOGPATH)\" \
        -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
        -DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
@@ -155,7 +180,7 @@ liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS) -pthread
 liblxc_so_LDFLAGS = \
        -pthread \
        -shared \
-       -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
+       -Wl,-soname,liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@))
 
 liblxc_so_LDADD = $(CAP_LIBS) $(APPARMOR_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS)
 
@@ -167,14 +192,12 @@ endif
 bin_SCRIPTS = lxc-checkconfig
 
 EXTRA_DIST = \
-       lxc-ls \
        lxc-top.lua
 
+if ENABLE_DEPRECATED
 if ENABLE_PYTHON
-bin_SCRIPTS += lxc-ls
 bin_SCRIPTS += lxc-start-ephemeral
-else
-bin_SCRIPTS += legacy/lxc-ls
+endif
 endif
 
 bin_PROGRAMS = \
@@ -182,7 +205,7 @@ bin_PROGRAMS = \
        lxc-autostart \
        lxc-cgroup \
        lxc-checkpoint \
-       lxc-clone \
+       lxc-copy \
        lxc-config \
        lxc-console \
        lxc-create \
@@ -191,6 +214,7 @@ bin_PROGRAMS = \
        lxc-execute \
        lxc-freeze \
        lxc-info \
+       lxc-ls \
        lxc-monitor \
        lxc-snapshot \
        lxc-start \
@@ -201,6 +225,10 @@ bin_PROGRAMS = \
        lxc-usernsexec \
        lxc-wait
 
+if ENABLE_DEPRECATED
+bin_PROGRAMS += lxc-clone
+endif
+
 sbin_PROGRAMS = init.lxc
 pkglibexec_PROGRAMS = \
        lxc-monitord \
@@ -225,7 +253,8 @@ lxc_info_SOURCES = lxc_info.c
 init_lxc_SOURCES = lxc_init.c
 lxc_monitor_SOURCES = lxc_monitor.c
 lxc_monitord_SOURCES = lxc_monitord.c
-lxc_clone_SOURCES = lxc_clone.c
+lxc_ls_SOURCES = lxc_ls.c
+lxc_copy_SOURCES = lxc_copy.c
 lxc_start_SOURCES = lxc_start.c
 lxc_stop_SOURCES = lxc_stop.c
 lxc_top_SOURCES = lxc_top.c
@@ -238,6 +267,14 @@ lxc_usernsexec_SOURCES = lxc_usernsexec.c
 lxc_user_nic_SOURCES = lxc_user_nic.c network.c network.h
 lxc_checkpoint_SOURCES = lxc_checkpoint.c
 
+if ENABLE_DEPRECATED
+lxc_clone_SOURCES = lxc_clone.c
+endif
+
+if !HAVE_GETSUBOPT
+lxc_copy_SOURCES += ../include/getsubopt.c ../include/getsubopt.h
+endif
+
 if HAVE_STATIC_LIBCAP
 sbin_PROGRAMS += init.lxc.static
 
@@ -257,10 +294,10 @@ endif
 install-exec-local: install-soPROGRAMS
        mkdir -p $(DESTDIR)$(datadir)/lxc
        install -c -m 644 lxc.functions $(DESTDIR)$(datadir)/lxc
-       mv $(DESTDIR)$(libdir)/liblxc.so $(DESTDIR)$(libdir)/liblxc.so.$(VERSION)
+       mv $(DESTDIR)$(libdir)/liblxc.so $(DESTDIR)$(libdir)/liblxc.so.@LXC_VERSION_ABI@
        cd $(DESTDIR)$(libdir); \
-       ln -sf liblxc.so.$(VERSION) liblxc.so.$(firstword $(subst ., ,$(VERSION))); \
-       ln -sf liblxc.so.$(firstword $(subst ., ,$(VERSION))) liblxc.so
+       ln -sf liblxc.so.@LXC_VERSION_ABI@ liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@)); \
+       ln -sf liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@)) liblxc.so
 
 install-exec-hook:
        chmod u+s $(DESTDIR)$(libexecdir)/lxc/lxc-user-nic
index 4449452..ee534a4 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -86,59 +96,60 @@ host_triplet = @host@
 @IS_BIONIC_TRUE@       ../include/lxcmntent.h
 
 @HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@am__append_2 = ../include/getline.h
+@HAVE_GETSUBOPT_FALSE@am__append_3 = ../include/getsubopt.h
 so_PROGRAMS = liblxc.so$(EXEEXT)
-@ENABLE_APPARMOR_TRUE@am__append_3 = lsm/apparmor.c
-@ENABLE_SELINUX_TRUE@am__append_4 = lsm/selinux.c
-@ENABLE_CGMANAGER_TRUE@am__append_5 = cgmanager.c
-@IS_BIONIC_TRUE@am__append_6 = \
+@ENABLE_APPARMOR_TRUE@am__append_4 = lsm/apparmor.c
+@ENABLE_SELINUX_TRUE@am__append_5 = lsm/selinux.c
+@ENABLE_CGMANAGER_TRUE@am__append_6 = cgmanager.c
+@IS_BIONIC_TRUE@am__append_7 = \
 @IS_BIONIC_TRUE@       ../include/ifaddrs.c ../include/ifaddrs.h \
 @IS_BIONIC_TRUE@       ../include/openpty.c ../include/openpty.h \
 @IS_BIONIC_TRUE@       ../include/lxcmntent.c ../include/lxcmntent.h
 
-@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@am__append_7 = ../include/getline.c ../include/getline.h
-@ENABLE_APPARMOR_TRUE@am__append_8 = -DHAVE_APPARMOR
-@ENABLE_CGMANAGER_TRUE@am__append_9 = -DHAVE_CGMANAGER
-@ENABLE_SELINUX_TRUE@am__append_10 = -DHAVE_SELINUX
-@USE_CONFIGPATH_LOGS_TRUE@am__append_11 = -DUSE_CONFIGPATH_LOGS
-@ENABLE_SECCOMP_TRUE@am__append_12 = -DHAVE_SECCOMP $(SECCOMP_CFLAGS)
-@ENABLE_SECCOMP_TRUE@am__append_13 = seccomp.c
-@ENABLE_CGMANAGER_TRUE@am__append_14 = $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
-@ENABLE_CGMANAGER_TRUE@am__append_15 = $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
-@ENABLE_PYTHON_TRUE@am__append_16 = lxc-ls lxc-start-ephemeral
-@ENABLE_PYTHON_FALSE@am__append_17 = legacy/lxc-ls
+@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@am__append_8 = ../include/getline.c ../include/getline.h
+@ENABLE_APPARMOR_TRUE@am__append_9 = -DHAVE_APPARMOR
+@ENABLE_CGMANAGER_TRUE@am__append_10 = -DHAVE_CGMANAGER
+@ENABLE_SELINUX_TRUE@am__append_11 = -DHAVE_SELINUX
+@USE_CONFIGPATH_LOGS_TRUE@am__append_12 = -DUSE_CONFIGPATH_LOGS
+@ENABLE_SECCOMP_TRUE@am__append_13 = -DHAVE_SECCOMP $(SECCOMP_CFLAGS)
+@ENABLE_SECCOMP_TRUE@am__append_14 = seccomp.c
+@ENABLE_CGMANAGER_TRUE@am__append_15 = $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
+@ENABLE_CGMANAGER_TRUE@am__append_16 = $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
+@ENABLE_DEPRECATED_TRUE@@ENABLE_PYTHON_TRUE@am__append_17 = lxc-start-ephemeral
 bin_PROGRAMS = lxc-attach$(EXEEXT) lxc-autostart$(EXEEXT) \
-       lxc-cgroup$(EXEEXT) lxc-checkpoint$(EXEEXT) lxc-clone$(EXEEXT) \
+       lxc-cgroup$(EXEEXT) lxc-checkpoint$(EXEEXT) lxc-copy$(EXEEXT) \
        lxc-config$(EXEEXT) lxc-console$(EXEEXT) lxc-create$(EXEEXT) \
        lxc-destroy$(EXEEXT) lxc-device$(EXEEXT) lxc-execute$(EXEEXT) \
-       lxc-freeze$(EXEEXT) lxc-info$(EXEEXT) lxc-monitor$(EXEEXT) \
-       lxc-snapshot$(EXEEXT) lxc-start$(EXEEXT) lxc-stop$(EXEEXT) \
-       lxc-top$(EXEEXT) lxc-unfreeze$(EXEEXT) lxc-unshare$(EXEEXT) \
-       lxc-usernsexec$(EXEEXT) lxc-wait$(EXEEXT)
-sbin_PROGRAMS = init.lxc$(EXEEXT) $(am__EXEEXT_1)
+       lxc-freeze$(EXEEXT) lxc-info$(EXEEXT) lxc-ls$(EXEEXT) \
+       lxc-monitor$(EXEEXT) lxc-snapshot$(EXEEXT) lxc-start$(EXEEXT) \
+       lxc-stop$(EXEEXT) lxc-top$(EXEEXT) lxc-unfreeze$(EXEEXT) \
+       lxc-unshare$(EXEEXT) lxc-usernsexec$(EXEEXT) lxc-wait$(EXEEXT) \
+       $(am__EXEEXT_1)
+@ENABLE_DEPRECATED_TRUE@am__append_18 = lxc-clone
+sbin_PROGRAMS = init.lxc$(EXEEXT) $(am__EXEEXT_2)
 pkglibexec_PROGRAMS = lxc-monitord$(EXEEXT) lxc-user-nic$(EXEEXT)
-@ENABLE_RPATH_TRUE@am__append_18 = -Wl,-rpath -Wl,$(libdir)
-@HAVE_STATIC_LIBCAP_TRUE@am__append_19 = init.lxc.static
-@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@@HAVE_STATIC_LIBCAP_TRUE@am__append_20 = ../include/getline.c
+@ENABLE_RPATH_TRUE@am__append_19 = -Wl,-rpath -Wl,$(libdir)
+@HAVE_GETSUBOPT_FALSE@am__append_20 = ../include/getsubopt.c ../include/getsubopt.h
+@HAVE_STATIC_LIBCAP_TRUE@am__append_21 = init.lxc.static
+@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@@HAVE_STATIC_LIBCAP_TRUE@am__append_22 = ../include/getline.c
 subdir = src/lxc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-checkconfig.in $(srcdir)/lxc-ls.in \
-       $(srcdir)/lxc-start-ephemeral.in $(srcdir)/lxc.functions.in \
-       $(srcdir)/version.h.in $(top_srcdir)/config/depcomp \
-       $(am__noinst_HEADERS_DIST) $(pkginclude_HEADERS)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__noinst_HEADERS_DIST) \
+       $(pkginclude_HEADERS) $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
-CONFIG_CLEAN_FILES = lxc-checkconfig lxc-ls lxc-start-ephemeral \
-       lxc.functions version.h
+CONFIG_CLEAN_FILES = lxc-checkconfig lxc-start-ephemeral lxc.functions \
+       version.h
 CONFIG_CLEAN_VPATH_FILES =
+@ENABLE_DEPRECATED_TRUE@am__EXEEXT_1 = lxc-clone$(EXEEXT)
 am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" \
        "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(sodir)" \
        "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgincludedir)"
-@HAVE_STATIC_LIBCAP_TRUE@am__EXEEXT_1 = init.lxc.static$(EXEEXT)
+@HAVE_STATIC_LIBCAP_TRUE@am__EXEEXT_2 = init.lxc.static$(EXEEXT)
 PROGRAMS = $(bin_PROGRAMS) $(pkglibexec_PROGRAMS) $(sbin_PROGRAMS) \
        $(so_PROGRAMS)
 am_init_lxc_OBJECTS = lxc_init.$(OBJEXT)
@@ -160,21 +171,27 @@ init_lxc_static_OBJECTS = $(am_init_lxc_static_OBJECTS)
 init_lxc_static_DEPENDENCIES =
 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 \
-       monitor.c monitor.h console.c freezer.c error.h error.c \
-       parse.c parse.h cgfs.c cgroup.c cgroup.h lxc.h initutils.c \
-       initutils.h utils.c utils.h sync.c sync.h namespace.h \
-       namespace.c conf.c conf.h confile.c confile.h list.h state.c \
-       state.h log.c log.h attach.c attach.h criu.c criu.h network.c \
-       network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h caps.c caps.h \
-       lxcseccomp.h mainloop.c mainloop.h af_unix.c af_unix.h \
-       lxcutmp.c lxcutmp.h lxclock.h lxclock.c lxccontainer.c \
-       lxccontainer.h version.h lsm/nop.c lsm/lsm.h lsm/lsm.c \
-       lsm/apparmor.c lsm/selinux.c cgmanager.c ../include/ifaddrs.c \
-       ../include/ifaddrs.h ../include/openpty.c ../include/openpty.h \
-       ../include/lxcmntent.c ../include/lxcmntent.h \
-       ../include/getline.c ../include/getline.h seccomp.c
+am__liblxc_so_SOURCES_DIST = arguments.c arguments.h bdev/bdev.c \
+       bdev/bdev.h bdev/lxcaufs.c bdev/lxcaufs.h bdev/lxcbtrfs.c \
+       bdev/lxcbtrfs.h bdev/lxcdir.c bdev/lxcdir.h bdev/lxcloop.c \
+       bdev/lxcloop.h bdev/lxclvm.c bdev/lxclvm.h bdev/lxcnbd.c \
+       bdev/lxcnbd.h bdev/lxcoverlay.c bdev/lxcoverlay.h \
+       bdev/lxcrbd.c bdev/lxcrbd.h bdev/lxcrsync.c bdev/lxcrsync.h \
+       bdev/lxczfs.c bdev/lxczfs.h commands.c commands.h start.c \
+       start.h execute.c monitor.c monitor.h console.c freezer.c \
+       error.h error.c parse.c parse.h cgfs.c cgfsng.c cgroup.c \
+       cgroup.h lxc.h initutils.c initutils.h utils.c utils.h sync.c \
+       sync.h namespace.h namespace.c conf.c conf.h confile.c \
+       confile.h list.h state.c state.h log.c log.h attach.c attach.h \
+       criu.c criu.h network.c network.h nl.c nl.h rtnl.c rtnl.h \
+       genl.c genl.h caps.c caps.h lxcseccomp.h mainloop.c mainloop.h \
+       af_unix.c af_unix.h lxcutmp.c lxcutmp.h lxclock.h lxclock.c \
+       lxccontainer.c lxccontainer.h version.h lsm/nop.c lsm/lsm.h \
+       lsm/lsm.c lsm/apparmor.c lsm/selinux.c cgmanager.c \
+       ../include/ifaddrs.c ../include/ifaddrs.h ../include/openpty.c \
+       ../include/openpty.h ../include/lxcmntent.c \
+       ../include/lxcmntent.h ../include/getline.c \
+       ../include/getline.h seccomp.c
 @ENABLE_APPARMOR_TRUE@am__objects_2 =  \
 @ENABLE_APPARMOR_TRUE@ lsm/liblxc_so-apparmor.$(OBJEXT)
 @ENABLE_SELINUX_TRUE@am__objects_3 = lsm/liblxc_so-selinux.$(OBJEXT)
@@ -188,24 +205,33 @@ am__objects_4 = lsm/liblxc_so-nop.$(OBJEXT) \
 @HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@am__objects_7 = ../include/liblxc_so-getline.$(OBJEXT)
 @ENABLE_SECCOMP_TRUE@am__objects_8 = liblxc_so-seccomp.$(OBJEXT)
 am_liblxc_so_OBJECTS = liblxc_so-arguments.$(OBJEXT) \
-       liblxc_so-bdev.$(OBJEXT) liblxc_so-commands.$(OBJEXT) \
+       bdev/liblxc_so-bdev.$(OBJEXT) bdev/liblxc_so-lxcaufs.$(OBJEXT) \
+       bdev/liblxc_so-lxcbtrfs.$(OBJEXT) \
+       bdev/liblxc_so-lxcdir.$(OBJEXT) \
+       bdev/liblxc_so-lxcloop.$(OBJEXT) \
+       bdev/liblxc_so-lxclvm.$(OBJEXT) \
+       bdev/liblxc_so-lxcnbd.$(OBJEXT) \
+       bdev/liblxc_so-lxcoverlay.$(OBJEXT) \
+       bdev/liblxc_so-lxcrbd.$(OBJEXT) \
+       bdev/liblxc_so-lxcrsync.$(OBJEXT) \
+       bdev/liblxc_so-lxczfs.$(OBJEXT) liblxc_so-commands.$(OBJEXT) \
        liblxc_so-start.$(OBJEXT) liblxc_so-execute.$(OBJEXT) \
        liblxc_so-monitor.$(OBJEXT) liblxc_so-console.$(OBJEXT) \
        liblxc_so-freezer.$(OBJEXT) liblxc_so-error.$(OBJEXT) \
        liblxc_so-parse.$(OBJEXT) liblxc_so-cgfs.$(OBJEXT) \
-       liblxc_so-cgroup.$(OBJEXT) liblxc_so-initutils.$(OBJEXT) \
-       liblxc_so-utils.$(OBJEXT) liblxc_so-sync.$(OBJEXT) \
-       liblxc_so-namespace.$(OBJEXT) liblxc_so-conf.$(OBJEXT) \
-       liblxc_so-confile.$(OBJEXT) liblxc_so-state.$(OBJEXT) \
-       liblxc_so-log.$(OBJEXT) liblxc_so-attach.$(OBJEXT) \
-       liblxc_so-criu.$(OBJEXT) liblxc_so-network.$(OBJEXT) \
-       liblxc_so-nl.$(OBJEXT) liblxc_so-rtnl.$(OBJEXT) \
-       liblxc_so-genl.$(OBJEXT) liblxc_so-caps.$(OBJEXT) \
-       liblxc_so-mainloop.$(OBJEXT) liblxc_so-af_unix.$(OBJEXT) \
-       liblxc_so-lxcutmp.$(OBJEXT) liblxc_so-lxclock.$(OBJEXT) \
-       liblxc_so-lxccontainer.$(OBJEXT) $(am__objects_4) \
-       $(am__objects_5) $(am__objects_6) $(am__objects_7) \
-       $(am__objects_8)
+       liblxc_so-cgfsng.$(OBJEXT) liblxc_so-cgroup.$(OBJEXT) \
+       liblxc_so-initutils.$(OBJEXT) liblxc_so-utils.$(OBJEXT) \
+       liblxc_so-sync.$(OBJEXT) liblxc_so-namespace.$(OBJEXT) \
+       liblxc_so-conf.$(OBJEXT) liblxc_so-confile.$(OBJEXT) \
+       liblxc_so-state.$(OBJEXT) liblxc_so-log.$(OBJEXT) \
+       liblxc_so-attach.$(OBJEXT) liblxc_so-criu.$(OBJEXT) \
+       liblxc_so-network.$(OBJEXT) liblxc_so-nl.$(OBJEXT) \
+       liblxc_so-rtnl.$(OBJEXT) liblxc_so-genl.$(OBJEXT) \
+       liblxc_so-caps.$(OBJEXT) liblxc_so-mainloop.$(OBJEXT) \
+       liblxc_so-af_unix.$(OBJEXT) liblxc_so-lxcutmp.$(OBJEXT) \
+       liblxc_so-lxclock.$(OBJEXT) liblxc_so-lxccontainer.$(OBJEXT) \
+       $(am__objects_4) $(am__objects_5) $(am__objects_6) \
+       $(am__objects_7) $(am__objects_8)
 liblxc_so_OBJECTS = $(am_liblxc_so_OBJECTS)
 am__DEPENDENCIES_1 =
 @ENABLE_CGMANAGER_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \
@@ -233,7 +259,8 @@ am_lxc_checkpoint_OBJECTS = lxc_checkpoint.$(OBJEXT)
 lxc_checkpoint_OBJECTS = $(am_lxc_checkpoint_OBJECTS)
 lxc_checkpoint_LDADD = $(LDADD)
 lxc_checkpoint_DEPENDENCIES = liblxc.so
-am_lxc_clone_OBJECTS = lxc_clone.$(OBJEXT)
+am__lxc_clone_SOURCES_DIST = lxc_clone.c
+@ENABLE_DEPRECATED_TRUE@am_lxc_clone_OBJECTS = lxc_clone.$(OBJEXT)
 lxc_clone_OBJECTS = $(am_lxc_clone_OBJECTS)
 lxc_clone_LDADD = $(LDADD)
 lxc_clone_DEPENDENCIES = liblxc.so
@@ -245,6 +272,13 @@ am_lxc_console_OBJECTS = lxc_console.$(OBJEXT)
 lxc_console_OBJECTS = $(am_lxc_console_OBJECTS)
 lxc_console_LDADD = $(LDADD)
 lxc_console_DEPENDENCIES = liblxc.so
+am__lxc_copy_SOURCES_DIST = lxc_copy.c ../include/getsubopt.c \
+       ../include/getsubopt.h
+@HAVE_GETSUBOPT_FALSE@am__objects_9 = ../include/getsubopt.$(OBJEXT)
+am_lxc_copy_OBJECTS = lxc_copy.$(OBJEXT) $(am__objects_9)
+lxc_copy_OBJECTS = $(am_lxc_copy_OBJECTS)
+lxc_copy_LDADD = $(LDADD)
+lxc_copy_DEPENDENCIES = liblxc.so
 am_lxc_create_OBJECTS = lxc_create.$(OBJEXT)
 lxc_create_OBJECTS = $(am_lxc_create_OBJECTS)
 lxc_create_LDADD = $(LDADD)
@@ -269,6 +303,10 @@ am_lxc_info_OBJECTS = lxc_info.$(OBJEXT)
 lxc_info_OBJECTS = $(am_lxc_info_OBJECTS)
 lxc_info_LDADD = $(LDADD)
 lxc_info_DEPENDENCIES = liblxc.so
+am_lxc_ls_OBJECTS = lxc_ls.$(OBJEXT)
+lxc_ls_OBJECTS = $(am_lxc_ls_OBJECTS)
+lxc_ls_LDADD = $(LDADD)
+lxc_ls_DEPENDENCIES = liblxc.so
 am_lxc_monitor_OBJECTS = lxc_monitor.$(OBJEXT)
 lxc_monitor_OBJECTS = $(am_lxc_monitor_OBJECTS)
 lxc_monitor_LDADD = $(LDADD)
@@ -378,37 +416,43 @@ SOURCES = $(init_lxc_SOURCES) $(init_lxc_static_SOURCES) \
        $(lxc_autostart_SOURCES) $(lxc_cgroup_SOURCES) \
        $(lxc_checkpoint_SOURCES) $(lxc_clone_SOURCES) \
        $(lxc_config_SOURCES) $(lxc_console_SOURCES) \
-       $(lxc_create_SOURCES) $(lxc_destroy_SOURCES) \
-       $(lxc_device_SOURCES) $(lxc_execute_SOURCES) \
-       $(lxc_freeze_SOURCES) $(lxc_info_SOURCES) \
-       $(lxc_monitor_SOURCES) $(lxc_monitord_SOURCES) \
-       $(lxc_snapshot_SOURCES) $(lxc_start_SOURCES) \
-       $(lxc_stop_SOURCES) $(lxc_top_SOURCES) $(lxc_unfreeze_SOURCES) \
-       $(lxc_unshare_SOURCES) $(lxc_user_nic_SOURCES) \
-       $(lxc_usernsexec_SOURCES) $(lxc_wait_SOURCES)
+       $(lxc_copy_SOURCES) $(lxc_create_SOURCES) \
+       $(lxc_destroy_SOURCES) $(lxc_device_SOURCES) \
+       $(lxc_execute_SOURCES) $(lxc_freeze_SOURCES) \
+       $(lxc_info_SOURCES) $(lxc_ls_SOURCES) $(lxc_monitor_SOURCES) \
+       $(lxc_monitord_SOURCES) $(lxc_snapshot_SOURCES) \
+       $(lxc_start_SOURCES) $(lxc_stop_SOURCES) $(lxc_top_SOURCES) \
+       $(lxc_unfreeze_SOURCES) $(lxc_unshare_SOURCES) \
+       $(lxc_user_nic_SOURCES) $(lxc_usernsexec_SOURCES) \
+       $(lxc_wait_SOURCES)
 DIST_SOURCES = $(init_lxc_SOURCES) $(am__init_lxc_static_SOURCES_DIST) \
        $(am__liblxc_so_SOURCES_DIST) $(lxc_attach_SOURCES) \
        $(lxc_autostart_SOURCES) $(lxc_cgroup_SOURCES) \
-       $(lxc_checkpoint_SOURCES) $(lxc_clone_SOURCES) \
+       $(lxc_checkpoint_SOURCES) $(am__lxc_clone_SOURCES_DIST) \
        $(lxc_config_SOURCES) $(lxc_console_SOURCES) \
-       $(lxc_create_SOURCES) $(lxc_destroy_SOURCES) \
-       $(lxc_device_SOURCES) $(lxc_execute_SOURCES) \
-       $(lxc_freeze_SOURCES) $(lxc_info_SOURCES) \
-       $(lxc_monitor_SOURCES) $(lxc_monitord_SOURCES) \
-       $(lxc_snapshot_SOURCES) $(lxc_start_SOURCES) \
-       $(lxc_stop_SOURCES) $(lxc_top_SOURCES) $(lxc_unfreeze_SOURCES) \
-       $(lxc_unshare_SOURCES) $(lxc_user_nic_SOURCES) \
-       $(lxc_usernsexec_SOURCES) $(lxc_wait_SOURCES)
+       $(am__lxc_copy_SOURCES_DIST) $(lxc_create_SOURCES) \
+       $(lxc_destroy_SOURCES) $(lxc_device_SOURCES) \
+       $(lxc_execute_SOURCES) $(lxc_freeze_SOURCES) \
+       $(lxc_info_SOURCES) $(lxc_ls_SOURCES) $(lxc_monitor_SOURCES) \
+       $(lxc_monitord_SOURCES) $(lxc_snapshot_SOURCES) \
+       $(lxc_start_SOURCES) $(lxc_stop_SOURCES) $(lxc_top_SOURCES) \
+       $(lxc_unfreeze_SOURCES) $(lxc_unshare_SOURCES) \
+       $(lxc_user_nic_SOURCES) $(lxc_usernsexec_SOURCES) \
+       $(lxc_wait_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-am__noinst_HEADERS_DIST = arguments.h attach.h bdev.h caps.h cgroup.h \
-       conf.h console.h error.h initutils.h list.h log.h lxc.h \
-       lxc-btrfs.h lxclock.h monitor.h namespace.h start.h state.h \
-       utils.h criu.h ../include/ifaddrs.h ../include/openpty.h \
-       ../include/lxcmntent.h ../include/getline.h
+am__noinst_HEADERS_DIST = arguments.h attach.h bdev/bdev.h \
+       bdev/lxcaufs.h bdev/lxcbtrfs.h bdev/lxcdir.h bdev/lxcloop.h \
+       bdev/lxclvm.h bdev/lxcnbd.h bdev/lxcoverlay.h bdev/lxcrbd.h \
+       bdev/lxcrsync.h bdev/lxczfs.h caps.h cgroup.h conf.h console.h \
+       error.h initutils.h list.h log.h lxc.h lxclock.h monitor.h \
+       namespace.h start.h state.h utils.h criu.h \
+       ../include/ifaddrs.h ../include/openpty.h \
+       ../include/lxcmntent.h ../include/getline.h \
+       ../include/getsubopt.h
 HEADERS = $(noinst_HEADERS) $(pkginclude_HEADERS)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
@@ -429,6 +473,9 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-checkconfig.in \
+       $(srcdir)/lxc-start-ephemeral.in $(srcdir)/lxc.functions.in \
+       $(srcdir)/version.h.in $(top_srcdir)/config/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -481,6 +528,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -494,6 +542,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -585,6 +634,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -598,52 +648,61 @@ pkginclude_HEADERS = \
        lxccontainer.h \
        version.h
 
-noinst_HEADERS = arguments.h attach.h bdev.h caps.h cgroup.h conf.h \
-       console.h error.h initutils.h list.h log.h lxc.h lxc-btrfs.h \
-       lxclock.h monitor.h namespace.h start.h state.h utils.h criu.h \
-       $(am__append_1) $(am__append_2)
+noinst_HEADERS = arguments.h attach.h bdev/bdev.h bdev/lxcaufs.h \
+       bdev/lxcbtrfs.h bdev/lxcdir.h bdev/lxcloop.h bdev/lxclvm.h \
+       bdev/lxcnbd.h bdev/lxcoverlay.h bdev/lxcrbd.h bdev/lxcrsync.h \
+       bdev/lxczfs.h caps.h cgroup.h conf.h console.h error.h \
+       initutils.h list.h log.h lxc.h lxclock.h monitor.h namespace.h \
+       start.h state.h utils.h criu.h $(am__append_1) $(am__append_2) \
+       $(am__append_3)
 sodir = $(libdir)
-LSM_SOURCES = lsm/nop.c lsm/lsm.h lsm/lsm.c $(am__append_3) \
-       $(am__append_4)
-liblxc_so_SOURCES = arguments.c arguments.h bdev.c bdev.h lxc-btrfs.h \
-       commands.c commands.h start.c start.h execute.c monitor.c \
-       monitor.h console.c freezer.c error.h error.c parse.c parse.h \
-       cgfs.c cgroup.c cgroup.h lxc.h initutils.c initutils.h utils.c \
-       utils.h sync.c sync.h namespace.h namespace.c conf.c conf.h \
-       confile.c confile.h list.h state.c state.h log.c log.h \
-       attach.c attach.h criu.c criu.h network.c network.h nl.c nl.h \
-       rtnl.c rtnl.h genl.c genl.h caps.c caps.h lxcseccomp.h \
-       mainloop.c mainloop.h af_unix.c af_unix.h lxcutmp.c lxcutmp.h \
-       lxclock.h lxclock.c lxccontainer.c lxccontainer.h version.h \
-       $(LSM_SOURCES) $(am__append_5) $(am__append_6) $(am__append_7) \
-       $(am__append_13)
+LSM_SOURCES = lsm/nop.c lsm/lsm.h lsm/lsm.c $(am__append_4) \
+       $(am__append_5)
+liblxc_so_SOURCES = arguments.c arguments.h bdev/bdev.c bdev/bdev.h \
+       bdev/lxcaufs.c bdev/lxcaufs.h bdev/lxcbtrfs.c bdev/lxcbtrfs.h \
+       bdev/lxcdir.c bdev/lxcdir.h bdev/lxcloop.c bdev/lxcloop.h \
+       bdev/lxclvm.c bdev/lxclvm.h bdev/lxcnbd.c bdev/lxcnbd.h \
+       bdev/lxcoverlay.c bdev/lxcoverlay.h bdev/lxcrbd.c \
+       bdev/lxcrbd.h bdev/lxcrsync.c bdev/lxcrsync.h bdev/lxczfs.c \
+       bdev/lxczfs.h commands.c commands.h start.c start.h execute.c \
+       monitor.c monitor.h console.c freezer.c error.h error.c \
+       parse.c parse.h cgfs.c cgfsng.c cgroup.c cgroup.h lxc.h \
+       initutils.c initutils.h utils.c utils.h sync.c sync.h \
+       namespace.h namespace.c conf.c conf.h confile.c confile.h \
+       list.h state.c state.h log.c log.h attach.c attach.h criu.c \
+       criu.h network.c network.h nl.c nl.h rtnl.c rtnl.h genl.c \
+       genl.h caps.c caps.h lxcseccomp.h mainloop.c mainloop.h \
+       af_unix.c af_unix.h lxcutmp.c lxcutmp.h lxclock.h lxclock.c \
+       lxccontainer.c lxccontainer.h version.h $(LSM_SOURCES) \
+       $(am__append_6) $(am__append_7) $(am__append_8) \
+       $(am__append_14)
 AM_CFLAGS = -I$(top_srcdir)/src -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
        -DLXCPATH=\"$(LXCPATH)\" \
        -DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \
        -DLXCINITDIR=\"$(LXCINITDIR)\" -DLIBEXECDIR=\"$(LIBEXECDIR)\" \
        -DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
+       -DLXCTEMPLATECONFIG=\"$(LXCTEMPLATECONFIG)\" \
        -DLOGPATH=\"$(LOGPATH)\" \
        -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
        -DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
        -DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\" \
        -DDEFAULT_CGROUP_PATTERN=\"$(DEFAULT_CGROUP_PATTERN)\" \
        -DRUNTIME_PATH=\"$(RUNTIME_PATH)\" -DSBINDIR=\"$(SBINDIR)\" \
-       $(am__append_8) $(am__append_9) $(am__append_10) \
-       $(am__append_11) $(am__append_12)
-liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS) -pthread $(am__append_15)
+       $(am__append_9) $(am__append_10) $(am__append_11) \
+       $(am__append_12) $(am__append_13)
+liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS) -pthread $(am__append_16)
 liblxc_so_LDFLAGS = \
        -pthread \
        -shared \
-       -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
+       -Wl,-soname,liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@))
 
 liblxc_so_LDADD = $(CAP_LIBS) $(APPARMOR_LIBS) $(SELINUX_LIBS) \
-       $(SECCOMP_LIBS) $(am__append_14)
-bin_SCRIPTS = lxc-checkconfig $(am__append_16) $(am__append_17)
+       $(SECCOMP_LIBS) $(am__append_15)
+bin_SCRIPTS = lxc-checkconfig $(am__append_17)
 EXTRA_DIST = \
-       lxc-ls \
        lxc-top.lua
 
-AM_LDFLAGS = -Wl,-E $(am__append_18)
+AM_LDFLAGS = -Wl,-E $(am__append_19)
 LDADD = liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
 lxc_attach_SOURCES = lxc_attach.c
 lxc_autostart_SOURCES = lxc_autostart.c
@@ -658,7 +717,8 @@ lxc_info_SOURCES = lxc_info.c
 init_lxc_SOURCES = lxc_init.c
 lxc_monitor_SOURCES = lxc_monitor.c
 lxc_monitord_SOURCES = lxc_monitord.c
-lxc_clone_SOURCES = lxc_clone.c
+lxc_ls_SOURCES = lxc_ls.c
+lxc_copy_SOURCES = lxc_copy.c $(am__append_20)
 lxc_start_SOURCES = lxc_start.c
 lxc_stop_SOURCES = lxc_stop.c
 lxc_top_SOURCES = lxc_top.c
@@ -670,9 +730,10 @@ lxc_snapshot_SOURCES = lxc_snapshot.c
 lxc_usernsexec_SOURCES = lxc_usernsexec.c
 lxc_user_nic_SOURCES = lxc_user_nic.c network.c network.h
 lxc_checkpoint_SOURCES = lxc_checkpoint.c
+@ENABLE_DEPRECATED_TRUE@lxc_clone_SOURCES = lxc_clone.c
 @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_SOURCES = lxc_init.c error.c \
 @HAVE_STATIC_LIBCAP_TRUE@      log.c initutils.c caps.c \
-@HAVE_STATIC_LIBCAP_TRUE@      $(am__append_20)
+@HAVE_STATIC_LIBCAP_TRUE@      $(am__append_22)
 @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
@@ -692,7 +753,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lxc/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu src/lxc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -712,8 +772,6 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 $(am__aclocal_m4_deps):
 lxc-checkconfig: $(top_builddir)/config.status $(srcdir)/lxc-checkconfig.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-lxc-ls: $(top_builddir)/config.status $(srcdir)/lxc-ls.in
-       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-start-ephemeral: $(top_builddir)/config.status $(srcdir)/lxc-start-ephemeral.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc.functions: $(top_builddir)/config.status $(srcdir)/lxc.functions.in
@@ -905,6 +963,34 @@ init.lxc$(EXEEXT): $(init_lxc_OBJECTS) $(init_lxc_DEPENDENCIES) $(EXTRA_init_lxc
 init.lxc.static$(EXEEXT): $(init_lxc_static_OBJECTS) $(init_lxc_static_DEPENDENCIES) $(EXTRA_init_lxc_static_DEPENDENCIES) 
        @rm -f init.lxc.static$(EXEEXT)
        $(AM_V_CCLD)$(init_lxc_static_LINK) $(init_lxc_static_OBJECTS) $(init_lxc_static_LDADD) $(LIBS)
+bdev/$(am__dirstamp):
+       @$(MKDIR_P) bdev
+       @: > bdev/$(am__dirstamp)
+bdev/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) bdev/$(DEPDIR)
+       @: > bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-bdev.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcaufs.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcbtrfs.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcdir.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcloop.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxclvm.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcnbd.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcoverlay.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcrbd.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxcrsync.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
+bdev/liblxc_so-lxczfs.$(OBJEXT): bdev/$(am__dirstamp) \
+       bdev/$(DEPDIR)/$(am__dirstamp)
 lsm/$(am__dirstamp):
        @$(MKDIR_P) lsm
        @: > lsm/$(am__dirstamp)
@@ -959,6 +1045,12 @@ lxc-config$(EXEEXT): $(lxc_config_OBJECTS) $(lxc_config_DEPENDENCIES) $(EXTRA_lx
 lxc-console$(EXEEXT): $(lxc_console_OBJECTS) $(lxc_console_DEPENDENCIES) $(EXTRA_lxc_console_DEPENDENCIES) 
        @rm -f lxc-console$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(lxc_console_OBJECTS) $(lxc_console_LDADD) $(LIBS)
+../include/getsubopt.$(OBJEXT): ../include/$(am__dirstamp) \
+       ../include/$(DEPDIR)/$(am__dirstamp)
+
+lxc-copy$(EXEEXT): $(lxc_copy_OBJECTS) $(lxc_copy_DEPENDENCIES) $(EXTRA_lxc_copy_DEPENDENCIES) 
+       @rm -f lxc-copy$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(lxc_copy_OBJECTS) $(lxc_copy_LDADD) $(LIBS)
 
 lxc-create$(EXEEXT): $(lxc_create_OBJECTS) $(lxc_create_DEPENDENCIES) $(EXTRA_lxc_create_DEPENDENCIES) 
        @rm -f lxc-create$(EXEEXT)
@@ -984,6 +1076,10 @@ lxc-info$(EXEEXT): $(lxc_info_OBJECTS) $(lxc_info_DEPENDENCIES) $(EXTRA_lxc_info
        @rm -f lxc-info$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(lxc_info_OBJECTS) $(lxc_info_LDADD) $(LIBS)
 
+lxc-ls$(EXEEXT): $(lxc_ls_OBJECTS) $(lxc_ls_DEPENDENCIES) $(EXTRA_lxc_ls_DEPENDENCIES) 
+       @rm -f lxc-ls$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(lxc_ls_OBJECTS) $(lxc_ls_LDADD) $(LIBS)
+
 lxc-monitor$(EXEEXT): $(lxc_monitor_OBJECTS) $(lxc_monitor_DEPENDENCIES) $(EXTRA_lxc_monitor_DEPENDENCIES) 
        @rm -f lxc-monitor$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(lxc_monitor_OBJECTS) $(lxc_monitor_LDADD) $(LIBS)
@@ -1066,11 +1162,13 @@ uninstall-binSCRIPTS:
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
        -rm -f ../include/*.$(OBJEXT)
+       -rm -f bdev/*.$(OBJEXT)
        -rm -f lsm/*.$(OBJEXT)
 
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/getsubopt.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@
@@ -1084,9 +1182,9 @@ distclean-compile:
 @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@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-bdev.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-caps.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-cgfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-cgfsng.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-cgmanager.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-cgroup.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-commands.Po@am__quote@
@@ -1122,6 +1220,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_clone.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_config.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_console.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_copy.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_create.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_destroy.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_device.Po@am__quote@
@@ -1129,6 +1228,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_freeze.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_info.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_init.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_ls.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_monitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_monitord.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxc_snapshot.Po@am__quote@
@@ -1141,6 +1241,17 @@ 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@bdev/$(DEPDIR)/liblxc_so-bdev.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcaufs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcdir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcloop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxclvm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcnbd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcrbd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxcrsync.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bdev/$(DEPDIR)/liblxc_so-lxczfs.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@
@@ -1260,19 +1371,159 @@ liblxc_so-arguments.obj: arguments.c
 @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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-arguments.obj `if test -f 'arguments.c'; then $(CYGPATH_W) 'arguments.c'; else $(CYGPATH_W) '$(srcdir)/arguments.c'; fi`
 
-liblxc_so-bdev.o: bdev.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-bdev.o -MD -MP -MF $(DEPDIR)/liblxc_so-bdev.Tpo -c -o liblxc_so-bdev.o `test -f 'bdev.c' || echo '$(srcdir)/'`bdev.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-bdev.Tpo $(DEPDIR)/liblxc_so-bdev.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev.c' object='liblxc_so-bdev.o' libtool=no @AMDEPBACKSLASH@
+bdev/liblxc_so-bdev.o: bdev/bdev.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-bdev.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-bdev.Tpo -c -o bdev/liblxc_so-bdev.o `test -f 'bdev/bdev.c' || echo '$(srcdir)/'`bdev/bdev.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-bdev.Tpo bdev/$(DEPDIR)/liblxc_so-bdev.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/bdev.c' object='bdev/liblxc_so-bdev.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-bdev.o `test -f 'bdev/bdev.c' || echo '$(srcdir)/'`bdev/bdev.c
+
+bdev/liblxc_so-bdev.obj: bdev/bdev.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-bdev.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-bdev.Tpo -c -o bdev/liblxc_so-bdev.obj `if test -f 'bdev/bdev.c'; then $(CYGPATH_W) 'bdev/bdev.c'; else $(CYGPATH_W) '$(srcdir)/bdev/bdev.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-bdev.Tpo bdev/$(DEPDIR)/liblxc_so-bdev.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/bdev.c' object='bdev/liblxc_so-bdev.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-bdev.o `test -f 'bdev.c' || echo '$(srcdir)/'`bdev.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-bdev.obj `if test -f 'bdev/bdev.c'; then $(CYGPATH_W) 'bdev/bdev.c'; else $(CYGPATH_W) '$(srcdir)/bdev/bdev.c'; fi`
 
-liblxc_so-bdev.obj: bdev.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-bdev.obj -MD -MP -MF $(DEPDIR)/liblxc_so-bdev.Tpo -c -o liblxc_so-bdev.obj `if test -f 'bdev.c'; then $(CYGPATH_W) 'bdev.c'; else $(CYGPATH_W) '$(srcdir)/bdev.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-bdev.Tpo $(DEPDIR)/liblxc_so-bdev.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev.c' object='liblxc_so-bdev.obj' libtool=no @AMDEPBACKSLASH@
+bdev/liblxc_so-lxcaufs.o: bdev/lxcaufs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcaufs.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcaufs.Tpo -c -o bdev/liblxc_so-lxcaufs.o `test -f 'bdev/lxcaufs.c' || echo '$(srcdir)/'`bdev/lxcaufs.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcaufs.Tpo bdev/$(DEPDIR)/liblxc_so-lxcaufs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcaufs.c' object='bdev/liblxc_so-lxcaufs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-bdev.obj `if test -f 'bdev.c'; then $(CYGPATH_W) 'bdev.c'; else $(CYGPATH_W) '$(srcdir)/bdev.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcaufs.o `test -f 'bdev/lxcaufs.c' || echo '$(srcdir)/'`bdev/lxcaufs.c
+
+bdev/liblxc_so-lxcaufs.obj: bdev/lxcaufs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcaufs.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcaufs.Tpo -c -o bdev/liblxc_so-lxcaufs.obj `if test -f 'bdev/lxcaufs.c'; then $(CYGPATH_W) 'bdev/lxcaufs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcaufs.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcaufs.Tpo bdev/$(DEPDIR)/liblxc_so-lxcaufs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcaufs.c' object='bdev/liblxc_so-lxcaufs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcaufs.obj `if test -f 'bdev/lxcaufs.c'; then $(CYGPATH_W) 'bdev/lxcaufs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcaufs.c'; fi`
+
+bdev/liblxc_so-lxcbtrfs.o: bdev/lxcbtrfs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcbtrfs.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Tpo -c -o bdev/liblxc_so-lxcbtrfs.o `test -f 'bdev/lxcbtrfs.c' || echo '$(srcdir)/'`bdev/lxcbtrfs.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Tpo bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcbtrfs.c' object='bdev/liblxc_so-lxcbtrfs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcbtrfs.o `test -f 'bdev/lxcbtrfs.c' || echo '$(srcdir)/'`bdev/lxcbtrfs.c
+
+bdev/liblxc_so-lxcbtrfs.obj: bdev/lxcbtrfs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcbtrfs.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Tpo -c -o bdev/liblxc_so-lxcbtrfs.obj `if test -f 'bdev/lxcbtrfs.c'; then $(CYGPATH_W) 'bdev/lxcbtrfs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcbtrfs.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Tpo bdev/$(DEPDIR)/liblxc_so-lxcbtrfs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcbtrfs.c' object='bdev/liblxc_so-lxcbtrfs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcbtrfs.obj `if test -f 'bdev/lxcbtrfs.c'; then $(CYGPATH_W) 'bdev/lxcbtrfs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcbtrfs.c'; fi`
+
+bdev/liblxc_so-lxcdir.o: bdev/lxcdir.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcdir.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcdir.Tpo -c -o bdev/liblxc_so-lxcdir.o `test -f 'bdev/lxcdir.c' || echo '$(srcdir)/'`bdev/lxcdir.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcdir.Tpo bdev/$(DEPDIR)/liblxc_so-lxcdir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcdir.c' object='bdev/liblxc_so-lxcdir.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcdir.o `test -f 'bdev/lxcdir.c' || echo '$(srcdir)/'`bdev/lxcdir.c
+
+bdev/liblxc_so-lxcdir.obj: bdev/lxcdir.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcdir.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcdir.Tpo -c -o bdev/liblxc_so-lxcdir.obj `if test -f 'bdev/lxcdir.c'; then $(CYGPATH_W) 'bdev/lxcdir.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcdir.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcdir.Tpo bdev/$(DEPDIR)/liblxc_so-lxcdir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcdir.c' object='bdev/liblxc_so-lxcdir.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcdir.obj `if test -f 'bdev/lxcdir.c'; then $(CYGPATH_W) 'bdev/lxcdir.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcdir.c'; fi`
+
+bdev/liblxc_so-lxcloop.o: bdev/lxcloop.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcloop.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcloop.Tpo -c -o bdev/liblxc_so-lxcloop.o `test -f 'bdev/lxcloop.c' || echo '$(srcdir)/'`bdev/lxcloop.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcloop.Tpo bdev/$(DEPDIR)/liblxc_so-lxcloop.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcloop.c' object='bdev/liblxc_so-lxcloop.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcloop.o `test -f 'bdev/lxcloop.c' || echo '$(srcdir)/'`bdev/lxcloop.c
+
+bdev/liblxc_so-lxcloop.obj: bdev/lxcloop.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcloop.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcloop.Tpo -c -o bdev/liblxc_so-lxcloop.obj `if test -f 'bdev/lxcloop.c'; then $(CYGPATH_W) 'bdev/lxcloop.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcloop.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcloop.Tpo bdev/$(DEPDIR)/liblxc_so-lxcloop.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcloop.c' object='bdev/liblxc_so-lxcloop.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcloop.obj `if test -f 'bdev/lxcloop.c'; then $(CYGPATH_W) 'bdev/lxcloop.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcloop.c'; fi`
+
+bdev/liblxc_so-lxclvm.o: bdev/lxclvm.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxclvm.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxclvm.Tpo -c -o bdev/liblxc_so-lxclvm.o `test -f 'bdev/lxclvm.c' || echo '$(srcdir)/'`bdev/lxclvm.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxclvm.Tpo bdev/$(DEPDIR)/liblxc_so-lxclvm.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxclvm.c' object='bdev/liblxc_so-lxclvm.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxclvm.o `test -f 'bdev/lxclvm.c' || echo '$(srcdir)/'`bdev/lxclvm.c
+
+bdev/liblxc_so-lxclvm.obj: bdev/lxclvm.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxclvm.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxclvm.Tpo -c -o bdev/liblxc_so-lxclvm.obj `if test -f 'bdev/lxclvm.c'; then $(CYGPATH_W) 'bdev/lxclvm.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxclvm.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxclvm.Tpo bdev/$(DEPDIR)/liblxc_so-lxclvm.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxclvm.c' object='bdev/liblxc_so-lxclvm.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxclvm.obj `if test -f 'bdev/lxclvm.c'; then $(CYGPATH_W) 'bdev/lxclvm.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxclvm.c'; fi`
+
+bdev/liblxc_so-lxcnbd.o: bdev/lxcnbd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcnbd.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcnbd.Tpo -c -o bdev/liblxc_so-lxcnbd.o `test -f 'bdev/lxcnbd.c' || echo '$(srcdir)/'`bdev/lxcnbd.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcnbd.Tpo bdev/$(DEPDIR)/liblxc_so-lxcnbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcnbd.c' object='bdev/liblxc_so-lxcnbd.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcnbd.o `test -f 'bdev/lxcnbd.c' || echo '$(srcdir)/'`bdev/lxcnbd.c
+
+bdev/liblxc_so-lxcnbd.obj: bdev/lxcnbd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcnbd.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcnbd.Tpo -c -o bdev/liblxc_so-lxcnbd.obj `if test -f 'bdev/lxcnbd.c'; then $(CYGPATH_W) 'bdev/lxcnbd.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcnbd.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcnbd.Tpo bdev/$(DEPDIR)/liblxc_so-lxcnbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcnbd.c' object='bdev/liblxc_so-lxcnbd.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcnbd.obj `if test -f 'bdev/lxcnbd.c'; then $(CYGPATH_W) 'bdev/lxcnbd.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcnbd.c'; fi`
+
+bdev/liblxc_so-lxcoverlay.o: bdev/lxcoverlay.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcoverlay.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Tpo -c -o bdev/liblxc_so-lxcoverlay.o `test -f 'bdev/lxcoverlay.c' || echo '$(srcdir)/'`bdev/lxcoverlay.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Tpo bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcoverlay.c' object='bdev/liblxc_so-lxcoverlay.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcoverlay.o `test -f 'bdev/lxcoverlay.c' || echo '$(srcdir)/'`bdev/lxcoverlay.c
+
+bdev/liblxc_so-lxcoverlay.obj: bdev/lxcoverlay.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcoverlay.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Tpo -c -o bdev/liblxc_so-lxcoverlay.obj `if test -f 'bdev/lxcoverlay.c'; then $(CYGPATH_W) 'bdev/lxcoverlay.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcoverlay.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Tpo bdev/$(DEPDIR)/liblxc_so-lxcoverlay.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcoverlay.c' object='bdev/liblxc_so-lxcoverlay.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcoverlay.obj `if test -f 'bdev/lxcoverlay.c'; then $(CYGPATH_W) 'bdev/lxcoverlay.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcoverlay.c'; fi`
+
+bdev/liblxc_so-lxcrbd.o: bdev/lxcrbd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcrbd.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcrbd.Tpo -c -o bdev/liblxc_so-lxcrbd.o `test -f 'bdev/lxcrbd.c' || echo '$(srcdir)/'`bdev/lxcrbd.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcrbd.Tpo bdev/$(DEPDIR)/liblxc_so-lxcrbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcrbd.c' object='bdev/liblxc_so-lxcrbd.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcrbd.o `test -f 'bdev/lxcrbd.c' || echo '$(srcdir)/'`bdev/lxcrbd.c
+
+bdev/liblxc_so-lxcrbd.obj: bdev/lxcrbd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcrbd.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcrbd.Tpo -c -o bdev/liblxc_so-lxcrbd.obj `if test -f 'bdev/lxcrbd.c'; then $(CYGPATH_W) 'bdev/lxcrbd.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcrbd.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcrbd.Tpo bdev/$(DEPDIR)/liblxc_so-lxcrbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcrbd.c' object='bdev/liblxc_so-lxcrbd.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcrbd.obj `if test -f 'bdev/lxcrbd.c'; then $(CYGPATH_W) 'bdev/lxcrbd.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcrbd.c'; fi`
+
+bdev/liblxc_so-lxcrsync.o: bdev/lxcrsync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcrsync.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcrsync.Tpo -c -o bdev/liblxc_so-lxcrsync.o `test -f 'bdev/lxcrsync.c' || echo '$(srcdir)/'`bdev/lxcrsync.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcrsync.Tpo bdev/$(DEPDIR)/liblxc_so-lxcrsync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcrsync.c' object='bdev/liblxc_so-lxcrsync.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcrsync.o `test -f 'bdev/lxcrsync.c' || echo '$(srcdir)/'`bdev/lxcrsync.c
+
+bdev/liblxc_so-lxcrsync.obj: bdev/lxcrsync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxcrsync.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxcrsync.Tpo -c -o bdev/liblxc_so-lxcrsync.obj `if test -f 'bdev/lxcrsync.c'; then $(CYGPATH_W) 'bdev/lxcrsync.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcrsync.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxcrsync.Tpo bdev/$(DEPDIR)/liblxc_so-lxcrsync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxcrsync.c' object='bdev/liblxc_so-lxcrsync.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxcrsync.obj `if test -f 'bdev/lxcrsync.c'; then $(CYGPATH_W) 'bdev/lxcrsync.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxcrsync.c'; fi`
+
+bdev/liblxc_so-lxczfs.o: bdev/lxczfs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxczfs.o -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxczfs.Tpo -c -o bdev/liblxc_so-lxczfs.o `test -f 'bdev/lxczfs.c' || echo '$(srcdir)/'`bdev/lxczfs.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxczfs.Tpo bdev/$(DEPDIR)/liblxc_so-lxczfs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxczfs.c' object='bdev/liblxc_so-lxczfs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxczfs.o `test -f 'bdev/lxczfs.c' || echo '$(srcdir)/'`bdev/lxczfs.c
+
+bdev/liblxc_so-lxczfs.obj: bdev/lxczfs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT bdev/liblxc_so-lxczfs.obj -MD -MP -MF bdev/$(DEPDIR)/liblxc_so-lxczfs.Tpo -c -o bdev/liblxc_so-lxczfs.obj `if test -f 'bdev/lxczfs.c'; then $(CYGPATH_W) 'bdev/lxczfs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxczfs.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) bdev/$(DEPDIR)/liblxc_so-lxczfs.Tpo bdev/$(DEPDIR)/liblxc_so-lxczfs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='bdev/lxczfs.c' object='bdev/liblxc_so-lxczfs.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o bdev/liblxc_so-lxczfs.obj `if test -f 'bdev/lxczfs.c'; then $(CYGPATH_W) 'bdev/lxczfs.c'; else $(CYGPATH_W) '$(srcdir)/bdev/lxczfs.c'; fi`
 
 liblxc_so-commands.o: commands.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-commands.o -MD -MP -MF $(DEPDIR)/liblxc_so-commands.Tpo -c -o liblxc_so-commands.o `test -f 'commands.c' || echo '$(srcdir)/'`commands.c
@@ -1400,6 +1651,20 @@ liblxc_so-cgfs.obj: cgfs.c
 @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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-cgfs.obj `if test -f 'cgfs.c'; then $(CYGPATH_W) 'cgfs.c'; else $(CYGPATH_W) '$(srcdir)/cgfs.c'; fi`
 
+liblxc_so-cgfsng.o: cgfsng.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-cgfsng.o -MD -MP -MF $(DEPDIR)/liblxc_so-cgfsng.Tpo -c -o liblxc_so-cgfsng.o `test -f 'cgfsng.c' || echo '$(srcdir)/'`cgfsng.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-cgfsng.Tpo $(DEPDIR)/liblxc_so-cgfsng.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='cgfsng.c' object='liblxc_so-cgfsng.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-cgfsng.o `test -f 'cgfsng.c' || echo '$(srcdir)/'`cgfsng.c
+
+liblxc_so-cgfsng.obj: cgfsng.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-cgfsng.obj -MD -MP -MF $(DEPDIR)/liblxc_so-cgfsng.Tpo -c -o liblxc_so-cgfsng.obj `if test -f 'cgfsng.c'; then $(CYGPATH_W) 'cgfsng.c'; else $(CYGPATH_W) '$(srcdir)/cgfsng.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-cgfsng.Tpo $(DEPDIR)/liblxc_so-cgfsng.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='cgfsng.c' object='liblxc_so-cgfsng.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) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-cgfsng.obj `if test -f 'cgfsng.c'; then $(CYGPATH_W) 'cgfsng.c'; else $(CYGPATH_W) '$(srcdir)/cgfsng.c'; fi`
+
 liblxc_so-cgroup.o: cgroup.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-cgroup.o -MD -MP -MF $(DEPDIR)/liblxc_so-cgroup.Tpo -c -o liblxc_so-cgroup.o `test -f 'cgroup.c' || echo '$(srcdir)/'`cgroup.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-cgroup.Tpo $(DEPDIR)/liblxc_so-cgroup.Po
@@ -1972,6 +2237,8 @@ distclean-generic:
        -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
        -rm -f ../include/$(DEPDIR)/$(am__dirstamp)
        -rm -f ../include/$(am__dirstamp)
+       -rm -f bdev/$(DEPDIR)/$(am__dirstamp)
+       -rm -f bdev/$(am__dirstamp)
        -rm -f lsm/$(DEPDIR)/$(am__dirstamp)
        -rm -f lsm/$(am__dirstamp)
 
@@ -1984,7 +2251,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-pkglibexecPROGRAMS \
        clean-sbinPROGRAMS clean-soPROGRAMS mostlyclean-am
 
 distclean: distclean-am
-       -rm -rf ../include/$(DEPDIR) ./$(DEPDIR) lsm/$(DEPDIR)
+       -rm -rf ../include/$(DEPDIR) ./$(DEPDIR) bdev/$(DEPDIR) lsm/$(DEPDIR)
        -rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
        distclean-tags
@@ -2033,7 +2300,7 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
-       -rm -rf ../include/$(DEPDIR) ./$(DEPDIR) lsm/$(DEPDIR)
+       -rm -rf ../include/$(DEPDIR) ./$(DEPDIR) bdev/$(DEPDIR) lsm/$(DEPDIR)
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
@@ -2076,14 +2343,16 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
        uninstall-pkgincludeHEADERS uninstall-pkglibexecPROGRAMS \
        uninstall-sbinPROGRAMS uninstall-soPROGRAMS
 
+.PRECIOUS: Makefile
+
 
 install-exec-local: install-soPROGRAMS
        mkdir -p $(DESTDIR)$(datadir)/lxc
        install -c -m 644 lxc.functions $(DESTDIR)$(datadir)/lxc
-       mv $(DESTDIR)$(libdir)/liblxc.so $(DESTDIR)$(libdir)/liblxc.so.$(VERSION)
+       mv $(DESTDIR)$(libdir)/liblxc.so $(DESTDIR)$(libdir)/liblxc.so.@LXC_VERSION_ABI@
        cd $(DESTDIR)$(libdir); \
-       ln -sf liblxc.so.$(VERSION) liblxc.so.$(firstword $(subst ., ,$(VERSION))); \
-       ln -sf liblxc.so.$(firstword $(subst ., ,$(VERSION))) liblxc.so
+       ln -sf liblxc.so.@LXC_VERSION_ABI@ liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@)); \
+       ln -sf liblxc.so.$(firstword $(subst ., ,@LXC_VERSION_ABI@)) liblxc.so
 
 install-exec-hook:
        chmod u+s $(DESTDIR)$(libexecdir)/lxc/lxc-user-nic
index cc85f86..6bc6fcd 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+
 #ifndef __LXC_ARGUMENTS_H
 #define __LXC_ARGUMENTS_H
 
 #include <getopt.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <sys/types.h>
 
 struct lxc_arguments;
 
@@ -86,13 +89,47 @@ struct lxc_arguments {
        char *fstype;
        uint64_t fssize;
        char *lvname, *vgname, *thinpool;
+       char *rbdname, *rbdpool;
        char *zfsroot, *lowerdir, *dir;
 
+       /* lxc-execute */
+       uid_t uid;
+       gid_t gid;
+
        /* auto-start */
        int all;
        int ignore_auto;
        int list;
-       char *groups;
+       char *groups; /* also used by lxc-ls */
+
+       /* lxc-snapshot and lxc-copy */
+       enum task {
+               CLONE,
+               DESTROY,
+               LIST,
+               RESTORE,
+               SNAP,
+               RENAME,
+       } task;
+       int print_comments;
+       char *commentfile;
+       char *newname;
+       char *newpath;
+       char *snapname;
+       int keepdata;
+       int keepname;
+       int keepmac;
+
+       /* lxc-ls */
+       char *ls_fancy_format;
+       char *ls_filter;
+       unsigned int ls_nesting; /* maximum allowed nesting level */
+       bool ls_active;
+       bool ls_fancy;
+       bool ls_frozen;
+       bool ls_line;
+       bool ls_running;
+       bool ls_stopped;
 
        /* remaining arguments */
        char *const *argv;
index 436ae7a..da5a557 100644 (file)
@@ -661,6 +661,7 @@ static bool fetch_seccomp(const char *name, const char *lxcpath,
                struct lxc_proc_context_info *i, lxc_attach_options_t *options)
 {
        struct lxc_container *c;
+       char *path;
 
        if (!(options->namespaces & CLONE_NEWNS) || !(options->attach_flags & LXC_ATTACH_LSM))
                return true;
@@ -669,8 +670,26 @@ static bool fetch_seccomp(const char *name, const char *lxcpath,
        if (!c)
                return false;
        i->container = c;
-       if (!c->lxc_conf)
+
+       /* Initialize an empty lxc_conf */
+       if (!c->set_config_item(c, "lxc.seccomp", "")) {
+               return false;
+       }
+
+       /* Fetch the current profile path over the cmd interface */
+       path = c->get_running_config_item(c, "lxc.seccomp");
+       if (!path) {
+               return true;
+       }
+
+       /* Copy the value into the new lxc_conf */
+       if (!c->set_config_item(c, "lxc.seccomp", path)) {
+               free(path);
                return false;
+       }
+       free(path);
+
+       /* Attempt to parse the resulting config */
        if (lxc_read_seccomp_config(c->lxc_conf) < 0) {
                ERROR("Error reading seccomp policy");
                return false;
@@ -701,6 +720,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
        int ipc_sockets[2];
        int procfd;
        signed long personality;
+       bool unshare_cgns = false;
 
        if (!options)
                options = &attach_static_default_options;
@@ -911,6 +931,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                rexit(-1);
        }
 
+       if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP && cgns_supported())
+               unshare_cgns = true;
+
        procfd = open("/proc", O_DIRECTORY | O_RDONLY);
        if (procfd < 0) {
                SYSERROR("Unable to open /proc");
@@ -938,6 +961,14 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                WARN("could not change directory to '%s'", new_cwd);
        free(cwd);
 
+       if (unshare_cgns) {
+               if (unshare(CLONE_NEWCGROUP) != 0) {
+                       SYSERROR("cgroupns unshare: permission denied");
+                       rexit(-1);
+               }
+               INFO("Unshared cgroup namespace");
+       }
+
        /* now create the real child process */
        {
                struct attach_clone_payload payload = {
@@ -1221,12 +1252,12 @@ int lxc_attach_run_shell(void* payload)
                user_shell = passwd->pw_shell;
 
        if (user_shell)
-               execlp(user_shell, user_shell, NULL);
+               execlp(user_shell, user_shell, (char *)NULL);
 
        /* executed if either no passwd entry or execvp fails,
         * we will fall back on /bin/sh as a default shell
         */
-       execlp("/bin/sh", "/bin/sh", NULL);
+       execlp("/bin/sh", "/bin/sh", (char *)NULL);
        SYSERROR("failed to exec shell");
        return -1;
 }
diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c
deleted file mode 100644 (file)
index 846fd82..0000000
+++ /dev/null
@@ -1,3723 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * this is all just a first shot for experiment.  If we go this route, much
- * should change.  bdev should be a directory with per-bdev file.  Things which
- * I'm doing by calling out to userspace should sometimes be done through
- * libraries like liblvm2
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <grp.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sched.h>
-#include <sys/mount.h>
-#include <sys/wait.h>
-#include <libgen.h>
-#include <linux/loop.h>
-#include <dirent.h>
-#include <sys/prctl.h>
-
-#include "lxc.h"
-#include "config.h"
-#include "conf.h"
-#include "bdev.h"
-#include "log.h"
-#include "error.h"
-#include "utils.h"
-#include "namespace.h"
-#include "parse.h"
-#include "lxclock.h"
-#include "lxc-btrfs.h"
-
-#ifndef BLKGETSIZE64
-#define BLKGETSIZE64 _IOR(0x12,114,size_t)
-#endif
-
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef LOOP_CTL_GET_FREE
-#define LOOP_CTL_GET_FREE 0x4C82
-#endif
-
-#define DEFAULT_FS_SIZE 1073741824
-#define DEFAULT_FSTYPE "ext3"
-
-lxc_log_define(bdev, lxc);
-
-struct ovl_rsync_data {
-       struct bdev *orig;
-       struct bdev *new;
-};
-
-struct rsync_data_char {
-       char *src;
-       char *dest;
-};
-
-static int do_rsync(const char *src, const char *dest)
-{
-       // call out to rsync
-       pid_t pid;
-       char *s;
-       size_t l;
-
-       pid = fork();
-       if (pid < 0)
-               return -1;
-       if (pid > 0)
-               return wait_for_pid(pid);
-
-       l = strlen(src) + 2;
-       s = malloc(l);
-       if (!s)
-               exit(1);
-       strcpy(s, src);
-       s[l-2] = '/';
-       s[l-1] = '\0';
-
-       execlp("rsync", "rsync", "-aHX", "--delete", s, dest, (char *)NULL);
-       exit(1);
-}
-
-/*
- * return block size of dev->src in units of bytes
- */
-static int blk_getsize(struct bdev *bdev, uint64_t *size)
-{
-       int fd, ret;
-       char *path = bdev->src;
-
-       if (strcmp(bdev->type, "loop") == 0)
-               path = bdev->src + 5;
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               return -1;
-
-       ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes
-       close(fd);
-       return ret;
-}
-
-/*
- * These are copied from conf.c.  However as conf.c will be moved to using
- * the callback system, they can be pulled from there eventually, so we
- * don't need to pollute utils.c with these low level functions
- */
-static int find_fstype_cb(char* buffer, void *data)
-{
-       struct cbarg {
-               const char *rootfs;
-               const char *target;
-               const char *options;
-       } *cbarg = data;
-
-       unsigned long mntflags;
-       char *mntdata;
-       char *fstype;
-
-       /* we don't try 'nodev' entries */
-       if (strstr(buffer, "nodev"))
-               return 0;
-
-       fstype = buffer;
-       fstype += lxc_char_left_gc(fstype, strlen(fstype));
-       fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
-
-       DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
-             cbarg->rootfs, cbarg->target, fstype);
-
-       if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return 0;
-       }
-
-       if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
-               DEBUG("mount failed with error: %s", strerror(errno));
-               free(mntdata);
-               return 0;
-       }
-
-       free(mntdata);
-
-       INFO("mounted '%s' on '%s', with fstype '%s'",
-            cbarg->rootfs, cbarg->target, fstype);
-
-       return 1;
-}
-
-static int mount_unknown_fs(const char *rootfs, const char *target,
-                                       const char *options)
-{
-       int i;
-
-       struct cbarg {
-               const char *rootfs;
-               const char *target;
-               const char *options;
-       } cbarg = {
-               .rootfs = rootfs,
-               .target = target,
-               .options = options,
-       };
-
-       /*
-        * find the filesystem type with brute force:
-        * first we check with /etc/filesystems, in case the modules
-        * are auto-loaded and fall back to the supported kernel fs
-        */
-       char *fsfile[] = {
-               "/etc/filesystems",
-               "/proc/filesystems",
-       };
-
-       for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
-
-               int ret;
-
-               if (access(fsfile[i], F_OK))
-                       continue;
-
-               ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
-               if (ret < 0) {
-                       ERROR("failed to parse '%s'", fsfile[i]);
-                       return -1;
-               }
-
-               if (ret)
-                       return 0;
-       }
-
-       ERROR("failed to determine fs type for '%s'", rootfs);
-       return -1;
-}
-
-static int do_mkfs(const char *path, const char *fstype)
-{
-       pid_t pid;
-
-       if ((pid = fork()) < 0) {
-               ERROR("error forking");
-               return -1;
-       }
-       if (pid > 0)
-               return wait_for_pid(pid);
-
-       // If the file is not a block device, we don't want mkfs to ask
-       // us about whether to proceed.
-       if (null_stdfds() < 0)
-               exit(1);
-       execlp("mkfs", "mkfs", "-t", fstype, path, NULL);
-       exit(1);
-}
-
-static char *linkderef(char *path, char *dest)
-{
-       struct stat sbuf;
-       ssize_t ret;
-
-       ret = stat(path, &sbuf);
-       if (ret < 0)
-               return NULL;
-       if (!S_ISLNK(sbuf.st_mode))
-               return path;
-       ret = readlink(path, dest, MAXPATHLEN);
-       if (ret < 0) {
-               SYSERROR("error reading link %s", path);
-               return NULL;
-       } else if (ret >= MAXPATHLEN) {
-               ERROR("link in %s too long", path);
-               return NULL;
-       }
-       dest[ret] = '\0';
-       return dest;
-}
-
-/*
- * Given a bdev (presumably blockdev-based), detect the fstype
- * by trying mounting (in a private mntns) it.
- * @bdev: bdev to investigate
- * @type: preallocated char* in which to write the fstype
- * @len: length of passed in char*
- * Returns length of fstype, of -1 on error
- */
-static int detect_fs(struct bdev *bdev, char *type, int len)
-{
-       int  p[2], ret;
-       size_t linelen;
-       pid_t pid;
-       FILE *f;
-       char *sp1, *sp2, *sp3, *line = NULL;
-       char *srcdev;
-
-       if (!bdev || !bdev->src || !bdev->dest)
-               return -1;
-
-       srcdev = bdev->src;
-       if (strcmp(bdev->type, "loop") == 0)
-               srcdev = bdev->src + 5;
-
-       ret = pipe(p);
-       if (ret < 0)
-               return -1;
-       if ((pid = fork()) < 0)
-               return -1;
-       if (pid > 0) {
-               int status;
-               close(p[1]);
-               memset(type, 0, len);
-               ret = read(p[0], type, len-1);
-               close(p[0]);
-               if (ret < 0) {
-                       SYSERROR("error reading from pipe");
-                       wait(&status);
-                       return -1;
-               } else if (ret == 0) {
-                       ERROR("child exited early - fstype not found");
-                       wait(&status);
-                       return -1;
-               }
-               wait(&status);
-               type[len-1] = '\0';
-               INFO("detected fstype %s for %s", type, srcdev);
-               return ret;
-       }
-
-       if (unshare(CLONE_NEWNS) < 0)
-               exit(1);
-
-       if (detect_shared_rootfs()) {
-               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
-                       SYSERROR("Failed to make / rslave");
-                       ERROR("Continuing...");
-               }
-       }
-
-       ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
-       if (ret < 0) {
-               ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest);
-               exit(1);
-       }
-       // if symlink, get the real dev name
-       char devpath[MAXPATHLEN];
-       char *l = linkderef(srcdev, devpath);
-       if (!l)
-               exit(1);
-       f = fopen("/proc/self/mounts", "r");
-       if (!f)
-               exit(1);
-       while (getline(&line, &linelen, f) != -1) {
-               sp1 = strchr(line, ' ');
-               if (!sp1)
-                       exit(1);
-               *sp1 = '\0';
-               if (strcmp(line, l))
-                       continue;
-               sp2 = strchr(sp1+1, ' ');
-               if (!sp2)
-                       exit(1);
-               *sp2 = '\0';
-               sp3 = strchr(sp2+1, ' ');
-               if (!sp3)
-                       exit(1);
-               *sp3 = '\0';
-               sp2++;
-               if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
-                       exit(1);
-               exit(0);
-       }
-       exit(1);
-}
-
-struct bdev_type {
-       const char *name;
-       const struct bdev_ops *ops;
-};
-
-static int dir_detect(const char *path)
-{
-       if (strncmp(path, "dir:", 4) == 0)
-               return 1; // take their word for it
-       if (is_dir(path))
-               return 1;
-       return 0;
-}
-
-//
-// XXXXXXX plain directory bind mount ops
-//
-static int dir_mount(struct bdev *bdev)
-{
-       unsigned long mntflags;
-       char *mntdata;
-       int ret;
-
-       if (strcmp(bdev->type, "dir"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
-       free(mntdata);
-       return ret;
-}
-
-static int dir_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "dir"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-/* the bulk of this needs to become a common helper */
-static char *dir_new_path(char *src, const char *oldname, const char *name,
-                       const char *oldpath, const char *lxcpath)
-{
-       char *ret, *p, *p2;
-       int l1, l2, nlen;
-
-       nlen = strlen(src) + 1;
-       l1 = strlen(oldpath);
-       p = src;
-       /* if src starts with oldpath, look for oldname only after
-        * that path */
-       if (strncmp(src, oldpath, l1) == 0) {
-               p += l1;
-               nlen += (strlen(lxcpath) - l1);
-       }
-       l2 = strlen(oldname);
-       while ((p = strstr(p, oldname)) != NULL) {
-               p += l2;
-               nlen += strlen(name) - l2;
-       }
-
-       ret = malloc(nlen);
-       if (!ret)
-               return NULL;
-
-       p = ret;
-       if (strncmp(src, oldpath, l1) == 0) {
-               p += sprintf(p, "%s", lxcpath);
-               src += l1;
-       }
-
-       while ((p2 = strstr(src, oldname)) != NULL) {
-               strncpy(p, src, p2-src); // copy text up to oldname
-               p += p2-src; // move target pointer (p)
-               p += sprintf(p, "%s", name); // print new name in place of oldname
-               src = p2 + l2;  // move src to end of oldname
-       }
-       sprintf(p, "%s", src);  // copy the rest of src
-       return ret;
-}
-
-/*
- * for a simple directory bind mount, we substitute the old container
- * name and paths for the new
- */
-static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       int len, ret;
-
-       if (snap) {
-               ERROR("directories cannot be snapshotted.  Try aufs or overlayfs.");
-               return -1;
-       }
-
-       if (!orig->dest || !orig->src)
-               return -1;
-
-       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
-       new->src = malloc(len);
-       if (!new->src)
-               return -1;
-       ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-       if ((new->dest = strdup(new->src)) == NULL)
-               return -1;
-
-       return 0;
-}
-
-static int dir_destroy(struct bdev *orig)
-{
-       if (lxc_rmdir_onedev(orig->src, NULL) < 0)
-               return -1;
-       return 0;
-}
-
-static int dir_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       if (specs && specs->dir)
-               bdev->src = strdup(specs->dir);
-       else
-               bdev->src = strdup(dest);
-       bdev->dest = strdup(dest);
-       if (!bdev->src || !bdev->dest) {
-               ERROR("Out of memory");
-               return -1;
-       }
-
-       if (mkdir_p(bdev->src, 0755) < 0) {
-               ERROR("Error creating %s", bdev->src);
-               return -1;
-       }
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static const struct bdev_ops dir_ops = {
-       .detect = &dir_detect,
-       .mount = &dir_mount,
-       .umount = &dir_umount,
-       .clone_paths = &dir_clonepaths,
-       .destroy = &dir_destroy,
-       .create = &dir_create,
-       .can_snapshot = false,
-       .can_backup = true,
-};
-
-
-//
-// XXXXXXX zfs ops
-// There are two ways we could do this.  We could always specify the
-// 'zfs device' (i.e. tank/lxc lxc/container) as rootfs.  But instead
-// (at least right now) we have lxc-create specify $lxcpath/$lxcname/rootfs
-// as the mountpoint, so that it is always mounted.
-//
-// That means 'mount' is really never needed and could be noop, but for the
-// sake of flexibility let's always bind-mount.
-//
-
-static int zfs_list_entry(const char *path, char *output, size_t inlen)
-{
-       struct lxc_popen_FILE *f;
-       int found=0;
-
-       f = lxc_popen("zfs list 2> /dev/null");
-       if (f == NULL) {
-               SYSERROR("popen failed");
-               return 0;
-       }
-       while (fgets(output, inlen, f->f)) {
-               if (strstr(output, path)) {
-                       found = 1;
-                       break;
-               }
-       }
-       (void) lxc_pclose(f);
-
-       return found;
-}
-
-static int zfs_detect(const char *path)
-{
-       char *output = malloc(LXC_LOG_BUFFER_SIZE);
-       int found;
-
-       if (!output) {
-               ERROR("out of memory");
-               return 0;
-       }
-       found = zfs_list_entry(path, output, LXC_LOG_BUFFER_SIZE);
-       free(output);
-       return found;
-}
-
-static int zfs_mount(struct bdev *bdev)
-{
-       unsigned long mntflags;
-       char *mntdata;
-       int ret;
-
-       if (strcmp(bdev->type, "zfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
-       free(mntdata);
-       return ret;
-}
-
-static int zfs_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "zfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int zfs_clone(const char *opath, const char *npath, const char *oname,
-                       const char *nname, const char *lxcpath, int snapshot)
-{
-       // use the 'zfs list | grep opath' entry to get the zfsroot
-       char output[MAXPATHLEN], option[MAXPATHLEN], *p;
-       const char *zfsroot = output;
-       int ret;
-       pid_t pid;
-
-       if (zfs_list_entry(opath, output, MAXPATHLEN)) {
-               // zfsroot is output up to ' '
-               if ((p = strchr(output, ' ')) == NULL)
-                       return -1;
-               *p = '\0';
-               if ((p = strrchr(output, '/')) == NULL)
-                       return -1;
-               *p = '\0';
-       } else
-               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
-
-       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs",
-               lxcpath, nname);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               return -1;
-
-       // zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname
-       if (!snapshot) {
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       char dev[MAXPATHLEN];
-
-                       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname);
-                       if (ret < 0  || ret >= MAXPATHLEN)
-                               exit(1);
-                       execlp("zfs", "zfs", "create", option, dev, NULL);
-                       exit(1);
-               }
-               return wait_for_pid(pid);
-       } else {
-               // if snapshot, do
-               // 'zfs snapshot zfsroot/oname@nname
-               // zfs clone zfsroot/oname@nname zfsroot/nname
-               char path1[MAXPATHLEN], path2[MAXPATHLEN];
-
-               ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", zfsroot,
-                       oname, nname);
-               if (ret < 0 || ret >= MAXPATHLEN)
-                       return -1;
-               (void) snprintf(path2, MAXPATHLEN, "%s/%s", zfsroot, nname);
-
-               // if the snapshot exists, delete it
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "destroy", path1, NULL);
-                       exit(1);
-               }
-               // it probably doesn't exist so destroy probably will fail.
-               (void) wait_for_pid(pid);
-
-               // run first (snapshot) command
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "snapshot", path1, NULL);
-                       exit(1);
-               }
-               if (wait_for_pid(pid) < 0)
-                       return -1;
-
-               // run second (clone) command
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "clone", option, path1, path2, NULL);
-                       exit(1);
-               }
-               return wait_for_pid(pid);
-       }
-}
-
-static int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       int len, ret;
-
-       if (!orig->src || !orig->dest)
-               return -1;
-
-       if (snap && strcmp(orig->type, "zfs")) {
-               ERROR("zfs snapshot from %s backing store is not supported",
-                       orig->type);
-               return -1;
-       }
-
-       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
-       new->src = malloc(len);
-       if (!new->src)
-               return -1;
-       ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-       if ((new->dest = strdup(new->src)) == NULL)
-               return -1;
-
-       return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
-}
-
-/*
- * TODO: detect whether this was a clone, and if so then also delete the
- * snapshot it was based on, so that we don't hold the original
- * container busy.
- */
-static int zfs_destroy(struct bdev *orig)
-{
-       pid_t pid;
-       char output[MAXPATHLEN], *p;
-
-       if ((pid = fork()) < 0)
-               return -1;
-       if (pid)
-               return wait_for_pid(pid);
-
-       if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
-               ERROR("Error: zfs entry for %s not found", orig->src);
-               return -1;
-       }
-
-       // zfs mount is output up to ' '
-       if ((p = strchr(output, ' ')) == NULL)
-               return -1;
-       *p = '\0';
-
-       execlp("zfs", "zfs", "destroy", output, NULL);
-       exit(1);
-}
-
-static int zfs_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       const char *zfsroot;
-       char option[MAXPATHLEN];
-       int ret;
-       pid_t pid;
-
-       if (!specs || !specs->zfs.zfsroot)
-               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
-       else
-               zfsroot = specs->zfs.zfsroot;
-
-       if (!(bdev->dest = strdup(dest))) {
-               ERROR("No mount target specified or out of memory");
-               return -1;
-       }
-       if (!(bdev->src = strdup(bdev->dest))) {
-               ERROR("out of memory");
-               return -1;
-       }
-
-       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               return -1;
-       if ((pid = fork()) < 0)
-               return -1;
-       if (pid)
-               return wait_for_pid(pid);
-
-       char dev[MAXPATHLEN];
-       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               exit(1);
-       execlp("zfs", "zfs", "create", option, dev, NULL);
-       exit(1);
-}
-
-static const struct bdev_ops zfs_ops = {
-       .detect = &zfs_detect,
-       .mount = &zfs_mount,
-       .umount = &zfs_umount,
-       .clone_paths = &zfs_clonepaths,
-       .destroy = &zfs_destroy,
-       .create = &zfs_create,
-       .can_snapshot = true,
-       .can_backup = true,
-};
-
-//
-// LVM ops
-//
-
-/*
- * Look at /sys/dev/block/maj:min/dm/uuid.  If it contains the hardcoded LVM
- * prefix "LVM-", then this is an lvm2 LV
- */
-static int lvm_detect(const char *path)
-{
-       char devp[MAXPATHLEN], buf[4];
-       FILE *fout;
-       int ret;
-       struct stat statbuf;
-
-       if (strncmp(path, "lvm:", 4) == 0)
-               return 1; // take their word for it
-
-       ret = stat(path, &statbuf);
-       if (ret != 0)
-               return 0;
-       if (!S_ISBLK(statbuf.st_mode))
-               return 0;
-
-       ret = snprintf(devp, MAXPATHLEN, "/sys/dev/block/%d:%d/dm/uuid",
-                       major(statbuf.st_rdev), minor(statbuf.st_rdev));
-       if (ret < 0 || ret >= MAXPATHLEN) {
-               ERROR("lvm uuid pathname too long");
-               return 0;
-       }
-       fout = fopen(devp, "r");
-       if (!fout)
-               return 0;
-       ret = fread(buf, 1, 4, fout);
-       fclose(fout);
-       if (ret != 4 || strncmp(buf, "LVM-", 4) != 0)
-               return 0;
-       return 1;
-}
-
-static int lvm_mount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "lvm"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       /* if we might pass in data sometime, then we'll have to enrich
-        * mount_unknown_fs */
-       return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
-}
-
-static int lvm_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "lvm"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int lvm_compare_lv_attr(const char *path, int pos, const char expected) {
-       struct lxc_popen_FILE *f;
-       int ret, len, status, start=0;
-       char *cmd, output[12];
-       const char *lvscmd = "lvs --unbuffered --noheadings -o lv_attr %s 2>/dev/null";
-
-       len = strlen(lvscmd) + strlen(path) - 1;
-       cmd = alloca(len);
-
-       ret = snprintf(cmd, len, lvscmd, path);
-       if (ret < 0 || ret >= len)
-               return -1;
-
-       f = lxc_popen(cmd);
-
-       if (f == NULL) {
-               SYSERROR("popen failed");
-               return -1;
-       }
-
-       ret = fgets(output, 12, f->f) == NULL;
-
-       status = lxc_pclose(f);
-
-       if (ret || WEXITSTATUS(status))
-               // Assume either vg or lvs do not exist, default
-               // comparison to false.
-               return 0;
-
-       len = strlen(output);
-       while(start < len && output[start] == ' ') start++;
-
-       if (start + pos < len && output[start + pos] == expected)
-               return 1;
-
-       return 0;
-}
-
-static int lvm_is_thin_volume(const char *path)
-{
-       return lvm_compare_lv_attr(path, 6, 't');
-}
-
-static int lvm_is_thin_pool(const char *path)
-{
-       return lvm_compare_lv_attr(path, 0, 't');
-}
-
-/*
- * path must be '/dev/$vg/$lv', $vg must be an existing VG, and $lv must not
- * yet exist.  This function will attempt to create /dev/$vg/$lv of size
- * $size. If thinpool is specified, we'll check for it's existence and if it's
- * a valid thin pool, and if so, we'll create the requested lv from that thin
- * pool.
- */
-static int do_lvm_create(const char *path, uint64_t size, const char *thinpool)
-{
-       int ret, pid, len;
-       char sz[24], *pathdup, *vg, *lv, *tp = NULL;
-
-       if ((pid = fork()) < 0) {
-               SYSERROR("failed fork");
-               return -1;
-       }
-       if (pid > 0)
-               return wait_for_pid(pid);
-
-       // specify bytes to lvcreate
-       ret = snprintf(sz, 24, "%"PRIu64"b", size);
-       if (ret < 0 || ret >= 24)
-               exit(1);
-
-       pathdup = strdup(path);
-       if (!pathdup)
-               exit(1);
-
-       lv = strrchr(pathdup, '/');
-       if (!lv)
-               exit(1);
-
-       *lv = '\0';
-       lv++;
-
-       vg = strrchr(pathdup, '/');
-       if (!vg)
-               exit(1);
-       vg++;
-
-       if (thinpool) {
-               len = strlen(pathdup) + strlen(thinpool) + 2;
-               tp = alloca(len);
-
-               ret = snprintf(tp, len, "%s/%s", pathdup, thinpool);
-               if (ret < 0 || ret >= len)
-                       exit(1);
-
-               ret = lvm_is_thin_pool(tp);
-               INFO("got %d for thin pool at path: %s", ret, tp);
-               if (ret < 0)
-                       exit(1);
-
-               if (!ret)
-                       tp = NULL;
-       }
-
-       if (!tp)
-           execlp("lvcreate", "lvcreate", "-L", sz, vg, "-n", lv, (char *)NULL);
-       else
-           execlp("lvcreate", "lvcreate", "--thinpool", tp, "-V", sz, vg, "-n", lv, (char *)NULL);
-
-       SYSERROR("execlp");
-       exit(1);
-}
-
-static int lvm_snapshot(const char *orig, const char *path, uint64_t size)
-{
-       int ret, pid;
-       char sz[24], *pathdup, *lv;
-
-       if ((pid = fork()) < 0) {
-               SYSERROR("failed fork");
-               return -1;
-       }
-       if (pid > 0)
-               return wait_for_pid(pid);
-
-       // specify bytes to lvcreate
-       ret = snprintf(sz, 24, "%"PRIu64"b", size);
-       if (ret < 0 || ret >= 24)
-               exit(1);
-
-       pathdup = strdup(path);
-       if (!pathdup)
-               exit(1);
-       lv = strrchr(pathdup, '/');
-       if (!lv) {
-               free(pathdup);
-               exit(1);
-       }
-       *lv = '\0';
-       lv++;
-
-       // check if the original lv is backed by a thin pool, in which case we
-       // cannot specify a size that's different from the original size.
-       ret = lvm_is_thin_volume(orig);
-       if (ret == -1) {
-               free(pathdup);
-               return -1;
-       }
-
-       if (!ret) {
-               ret = execlp("lvcreate", "lvcreate", "-s", "-L", sz, "-n", lv, orig, (char *)NULL);
-       } else {
-               ret = execlp("lvcreate", "lvcreate", "-s", "-n", lv, orig, (char *)NULL);
-       }
-
-       free(pathdup);
-       exit(1);
-}
-
-// this will return 1 for physical disks, qemu-nbd, loop, etc
-// right now only lvm is a block device
-static int is_blktype(struct bdev *b)
-{
-       if (strcmp(b->type, "lvm") == 0)
-               return 1;
-       return 0;
-}
-
-static int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       char fstype[100];
-       uint64_t size = newsize;
-       int len, ret;
-
-       if (!orig->src || !orig->dest)
-               return -1;
-
-       if (strcmp(orig->type, "lvm")) {
-               const char *vg;
-
-               if (snap) {
-                       ERROR("LVM snapshot from %s backing store is not supported",
-                               orig->type);
-                       return -1;
-               }
-               vg = lxc_global_config_value("lxc.bdev.lvm.vg");
-               len = strlen("/dev/") + strlen(vg) + strlen(cname) + 2;
-               if ((new->src = malloc(len)) == NULL)
-                       return -1;
-               ret = snprintf(new->src, len, "/dev/%s/%s", vg, cname);
-               if (ret < 0 || ret >= len)
-                       return -1;
-       } else {
-               new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath);
-               if (!new->src)
-                       return -1;
-       }
-
-       if (orig->mntopts) {
-               new->mntopts = strdup(orig->mntopts);
-               if (!new->mntopts)
-                       return -1;
-       }
-
-       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
-       new->dest = malloc(len);
-       if (!new->dest)
-               return -1;
-       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-       if (mkdir_p(new->dest, 0755) < 0)
-               return -1;
-
-       if (is_blktype(orig)) {
-               if (!newsize && blk_getsize(orig, &size) < 0) {
-                       ERROR("Error getting size of %s", orig->src);
-                       return -1;
-               }
-               if (detect_fs(orig, fstype, 100) < 0) {
-                       INFO("could not find fstype for %s, using ext3", orig->src);
-                       return -1;
-               }
-       } else {
-               sprintf(fstype, "ext3");
-               if (!newsize)
-                       size = DEFAULT_FS_SIZE;
-       }
-
-       if (snap) {
-               if (lvm_snapshot(orig->src, new->src, size) < 0) {
-                       ERROR("could not create %s snapshot of %s", new->src, orig->src);
-                       return -1;
-               }
-       } else {
-               if (do_lvm_create(new->src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) {
-                       ERROR("Error creating new lvm blockdev");
-                       return -1;
-               }
-               if (do_mkfs(new->src, fstype) < 0) {
-                       ERROR("Error creating filesystem type %s on %s", fstype,
-                               new->src);
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int lvm_destroy(struct bdev *orig)
-{
-       pid_t pid;
-
-       if ((pid = fork()) < 0)
-               return -1;
-       if (!pid) {
-               execlp("lvremove", "lvremove", "-f", orig->src, NULL);
-               exit(1);
-       }
-       return wait_for_pid(pid);
-}
-
-static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       const char *vg, *thinpool, *fstype, *lv = n;
-       uint64_t sz;
-       int ret, len;
-
-       if (!specs)
-               return -1;
-
-       vg = specs->lvm.vg;
-       if (!vg)
-               vg = lxc_global_config_value("lxc.bdev.lvm.vg");
-
-       thinpool = specs->lvm.thinpool;
-       if (!thinpool)
-               thinpool = lxc_global_config_value("lxc.bdev.lvm.thin_pool");
-
-       /* /dev/$vg/$lv */
-       if (specs->lvm.lv)
-               lv = specs->lvm.lv;
-
-       len = strlen(vg) + strlen(lv) + 7;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "/dev/%s/%s", vg, lv);
-       if (ret < 0 || ret >= len)
-               return -1;
-
-       // fssize is in bytes.
-       sz = specs->fssize;
-       if (!sz)
-               sz = DEFAULT_FS_SIZE;
-
-       if (do_lvm_create(bdev->src, sz, thinpool) < 0) {
-               ERROR("Error creating new lvm blockdev %s size %"PRIu64" bytes", bdev->src, sz);
-               return -1;
-       }
-
-       fstype = specs->fstype;
-       if (!fstype)
-               fstype = DEFAULT_FSTYPE;
-       if (do_mkfs(bdev->src, fstype) < 0) {
-               ERROR("Error creating filesystem type %s on %s", fstype,
-                       bdev->src);
-               return -1;
-       }
-       if (!(bdev->dest = strdup(dest)))
-               return -1;
-
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static const struct bdev_ops lvm_ops = {
-       .detect = &lvm_detect,
-       .mount = &lvm_mount,
-       .umount = &lvm_umount,
-       .clone_paths = &lvm_clonepaths,
-       .destroy = &lvm_destroy,
-       .create = &lvm_create,
-       .can_snapshot = true,
-       .can_backup = false,
-};
-
-/*
- * Return the full path of objid under dirid.  Let's say dirid is
- * /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c.  Then we will
- * return a/b/c.  If instead objid is for /lxc/c1/rootfs/a, we will
- * simply return a.
- */
-char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid,
-               char *name, int name_len)
-{
-       struct btrfs_ioctl_ino_lookup_args args;
-       int ret, e;
-       size_t len;
-       char *retpath;
-
-       memset(&args, 0, sizeof(args));
-       args.treeid = dir_id;
-       args.objectid = objid;
-
-       ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
-       e = errno;
-       if (ret) {
-               ERROR("%s: ERROR: Failed to lookup path for %llu %llu %s - %s\n",
-                                __func__, (unsigned long long) dir_id,
-                                (unsigned long long) objid,
-                                name, strerror(e));
-               return NULL;
-       } else
-               INFO("%s: got path for %llu %llu - %s\n", __func__,
-                       (unsigned long long) objid, (unsigned long long) dir_id,
-                       name);
-
-       if (args.name[0]) {
-               /*
-                * we're in a subdirectory of ref_tree, the kernel ioctl
-                * puts a / in there for us
-                */
-               len = strlen(args.name) + name_len + 2;
-               retpath = malloc(len);
-               if (!retpath)
-                       return NULL;
-               strcpy(retpath, args.name);
-               strcat(retpath, "/");
-               strncat(retpath, name, name_len);
-       } else {
-               /* we're at the root of ref_tree */
-               len = name_len + 1;
-               retpath = malloc(len);
-               if (!retpath)
-                       return NULL;
-               *retpath = '\0';
-               strncat(retpath, name, name_len);
-       }
-       return retpath;
-}
-
-//
-// btrfs ops
-//
-
-int btrfs_list_get_path_rootid(int fd, u64 *treeid)
-{
-       int  ret;
-       struct btrfs_ioctl_ino_lookup_args args;
-
-       memset(&args, 0, sizeof(args));
-       args.objectid = BTRFS_FIRST_FREE_OBJECTID;
-
-       ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
-       if (ret < 0) {
-               WARN("Warning: can't perform the search -%s\n",
-                               strerror(errno));
-               return ret;
-       }
-       *treeid = args.treeid;
-       return 0;
-}
-
-bool is_btrfs_fs(const char *path)
-{
-       int fd, ret;
-       struct btrfs_ioctl_space_args sargs;
-
-       // make sure this is a btrfs filesystem
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               return false;
-       sargs.space_slots = 0;
-       sargs.total_spaces = 0;
-       ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &sargs);
-       close(fd);
-       if (ret < 0)
-               return false;
-
-       return true;
-}
-
-static int btrfs_detect(const char *path)
-{
-       struct stat st;
-       int ret;
-
-       if (!is_btrfs_fs(path))
-               return 0;
-
-       // and make sure it's a subvolume.
-       ret = stat(path, &st);
-       if (ret < 0)
-               return 0;
-
-       if (st.st_ino == 256 && S_ISDIR(st.st_mode))
-               return 1;
-
-       return 0;
-}
-
-static int btrfs_mount(struct bdev *bdev)
-{
-       unsigned long mntflags;
-       char *mntdata;
-       int ret;
-
-       if (strcmp(bdev->type, "btrfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
-       free(mntdata);
-       return ret;
-}
-
-static int btrfs_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "btrfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int btrfs_subvolume_create(const char *path)
-{
-       int ret, fd = -1;
-       struct btrfs_ioctl_vol_args  args;
-       char *p, *newfull = strdup(path);
-
-       if (!newfull) {
-               ERROR("Error: out of memory");
-               return -1;
-       }
-
-       p = strrchr(newfull, '/');
-       if (!p) {
-               ERROR("bad path: %s", path);
-               free(newfull);
-               return -1;
-       }
-       *p = '\0';
-
-       fd = open(newfull, O_RDONLY);
-       if (fd < 0) {
-               ERROR("Error opening %s", newfull);
-               free(newfull);
-               return -1;
-       }
-
-       memset(&args, 0, sizeof(args));
-       strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
-       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
-       ret = ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args);
-       INFO("btrfs: snapshot create ioctl returned %d", ret);
-
-       free(newfull);
-       close(fd);
-       return ret;
-}
-
-static int btrfs_same_fs(const char *orig, const char *new) {
-       int fd_orig = -1, fd_new = -1, ret = -1;
-       struct btrfs_ioctl_fs_info_args orig_args, new_args;
-
-       fd_orig = open(orig, O_RDONLY);
-       if (fd_orig < 0) {
-               SYSERROR("Error opening original rootfs %s", orig);
-               goto out;
-       }
-       ret = ioctl(fd_orig, BTRFS_IOC_FS_INFO, &orig_args);
-       if (ret < 0) {
-               SYSERROR("BTRFS_IOC_FS_INFO %s", orig);
-               goto out;
-       }
-
-       fd_new = open(new, O_RDONLY);
-       if (fd_new < 0) {
-               SYSERROR("Error opening new container dir %s", new);
-               ret = -1;
-               goto out;
-       }
-       ret = ioctl(fd_new, BTRFS_IOC_FS_INFO, &new_args);
-       if (ret < 0) {
-               SYSERROR("BTRFS_IOC_FS_INFO %s", new);
-               goto out;
-       }
-
-       if (strncmp(orig_args.fsid, new_args.fsid, BTRFS_FSID_SIZE) != 0) {
-               ret = -1;
-               goto out;
-       }
-       ret = 0;
-out:
-       if (fd_new != -1)
-               close(fd_new);
-       if (fd_orig != -1)
-               close(fd_orig);
-       return ret;
-}
-
-static int btrfs_snapshot(const char *orig, const char *new)
-{
-       int fd = -1, fddst = -1, ret = -1;
-       struct btrfs_ioctl_vol_args_v2  args;
-       char *newdir, *newname, *newfull = NULL;
-
-       newfull = strdup(new);
-       if (!newfull) {
-               ERROR("Error: out of memory");
-               goto out;
-       }
-       // make sure the directory doesn't already exist
-       if (rmdir(newfull) < 0 && errno != ENOENT) {
-               SYSERROR("Error removing empty new rootfs");
-               goto out;
-       }
-       newname = basename(newfull);
-       newdir = dirname(newfull);
-       fd = open(orig, O_RDONLY);
-       if (fd < 0) {
-               SYSERROR("Error opening original rootfs %s", orig);
-               goto out;
-       }
-       fddst = open(newdir, O_RDONLY);
-       if (fddst < 0) {
-               SYSERROR("Error opening new container dir %s", newdir);
-               goto out;
-       }
-
-       memset(&args, 0, sizeof(args));
-       args.fd = fd;
-       strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
-       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
-       ret = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
-       INFO("btrfs: snapshot create ioctl returned %d", ret);
-
-out:
-       if (fddst != -1)
-               close(fddst);
-       if (fd != -1)
-               close(fd);
-       free(newfull);
-       return ret;
-}
-
-static int btrfs_snapshot_wrapper(void *data)
-{
-       struct rsync_data_char *arg = data;
-       if (setgid(0) < 0) {
-               ERROR("Failed to setgid to 0");
-               return -1;
-       }
-       if (setgroups(0, NULL) < 0)
-               WARN("Failed to clear groups");
-       if (setuid(0) < 0) {
-               ERROR("Failed to setuid to 0");
-               return -1;
-       }
-       return btrfs_snapshot(arg->src, arg->dest);
-}
-
-static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       if (!orig->dest || !orig->src)
-               return -1;
-
-       if (strcmp(orig->type, "btrfs")) {
-               int len, ret;
-               if (snap) {
-                       ERROR("btrfs snapshot from %s backing store is not supported",
-                               orig->type);
-                       return -1;
-               }
-               len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
-               new->src = malloc(len);
-               if (!new->src)
-                       return -1;
-               ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
-               if (ret < 0 || ret >= len)
-                       return -1;
-       } else {
-               // in case rootfs is in custom path, reuse it
-               if ((new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath)) == NULL)
-                       return -1;
-
-       }
-
-       if ((new->dest = strdup(new->src)) == NULL)
-               return -1;
-
-       if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
-               return -1;
-
-       if (snap) {
-               struct rsync_data_char sdata;
-               if (!am_unpriv())
-                       return btrfs_snapshot(orig->dest, new->dest);
-               sdata.dest = new->dest;
-               sdata.src = orig->dest;
-               return userns_exec_1(conf, btrfs_snapshot_wrapper, &sdata);
-       }
-
-       if (rmdir(new->dest) < 0 && errno != ENOENT) {
-               SYSERROR("removing %s", new->dest);
-               return -1;
-       }
-
-       return btrfs_subvolume_create(new->dest);
-}
-
-static int btrfs_do_destroy_subvol(const char *path)
-{
-       int ret, fd = -1;
-       struct btrfs_ioctl_vol_args  args;
-       char *p, *newfull = strdup(path);
-
-       if (!newfull) {
-               ERROR("Error: out of memory");
-               return -1;
-       }
-
-       p = strrchr(newfull, '/');
-       if (!p) {
-               ERROR("bad path: %s", path);
-               free(newfull);
-               return -1;
-       }
-       *p = '\0';
-
-       fd = open(newfull, O_RDONLY);
-       if (fd < 0) {
-               SYSERROR("Error opening %s", newfull);
-               free(newfull);
-               return -1;
-       }
-
-       memset(&args, 0, sizeof(args));
-       strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
-       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
-       ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
-       INFO("btrfs: snapshot destroy ioctl returned %d for %s", ret, path);
-       if (ret < 0 && errno == EPERM)
-               ERROR("Is the rootfs mounted with -o user_subvol_rm_allowed?");
-
-       free(newfull);
-       close(fd);
-       return ret;
-}
-
-struct mytree_node {
-       u64 objid;
-       u64 parentid;
-       char *name;
-       char *dirname;
-};
-
-struct my_btrfs_tree {
-       struct mytree_node *nodes;
-       int num;
-};
-
-static int get_btrfs_tree_idx(struct my_btrfs_tree *tree, u64 id)
-{
-       int i;
-       if (!tree)
-               return -1;
-       for (i = 0; i < tree->num; i++) {
-               if (tree->nodes[i].objid == id)
-                       return i;
-       }
-       return -1;
-}
-
-static struct my_btrfs_tree *create_my_btrfs_tree(u64 id, const char *path, int name_len)
-{
-       struct my_btrfs_tree *tree;
-
-       tree = malloc(sizeof(struct my_btrfs_tree));
-       if (!tree)
-               return NULL;
-       tree->nodes = malloc(sizeof(struct mytree_node));
-       if (!tree->nodes) {
-               free(tree);
-               return NULL;
-       }
-       tree->num = 1;
-       tree->nodes[0].dirname = NULL;
-       tree->nodes[0].name = strdup(path);
-       if (!tree->nodes[0].name) {
-               free(tree->nodes);
-               free(tree);
-               return NULL;
-       }
-       tree->nodes[0].parentid = 0;
-       tree->nodes[0].objid = id;
-       return tree;
-}
-
-static bool update_tree_node(struct mytree_node *n, u64 id, u64 parent, char *name,
-               int name_len, char *dirname)
-{
-       if (id)
-               n->objid = id;
-       if (parent)
-               n->parentid = parent;
-       if (name) {
-               n->name = malloc(name_len + 1);
-               if (!n->name)
-                       return false;
-               strncpy(n->name, name, name_len);
-               n->name[name_len] = '\0';
-       }
-       if (dirname) {
-               n->dirname = malloc(strlen(dirname) + 1);
-               if (!n->dirname) {
-                       free(n->name);
-                       return false;
-               }
-               strcpy(n->dirname, dirname);
-       }
-       return true;
-}
-
-static bool add_btrfs_tree_node(struct my_btrfs_tree *tree, u64 id, u64 parent,
-               char *name, int name_len, char *dirname)
-{
-       struct mytree_node *tmp;
-
-       int i = get_btrfs_tree_idx(tree, id);
-       if (i != -1)
-               return update_tree_node(&tree->nodes[i], id, parent, name,
-                               name_len, dirname);
-
-       tmp = realloc(tree->nodes, (tree->num+1) * sizeof(struct mytree_node));
-       if (!tmp)
-               return false;
-       tree->nodes = tmp;
-       memset(&tree->nodes[tree->num], 0, sizeof(struct mytree_node));
-       if (!update_tree_node(&tree->nodes[tree->num], id, parent, name,
-                               name_len, dirname))
-               return false;
-       tree->num++;
-       return true;
-}
-
-static void free_btrfs_tree(struct my_btrfs_tree *tree)
-{
-       int i;
-       if (!tree)
-               return;
-       for (i = 0; i < tree->num;  i++) {
-               free(tree->nodes[i].name);
-               free(tree->nodes[i].dirname);
-       }
-       free(tree->nodes);
-       free(tree);
-}
-
-/*
- * Given a @tree of subvolumes under @path, ask btrfs to remove each
- * subvolume
- */
-static bool do_remove_btrfs_children(struct my_btrfs_tree *tree, u64 root_id,
-               const char *path)
-{
-       int i;
-       char *newpath;
-       size_t len;
-
-       for (i = 0; i < tree->num; i++) {
-               if (tree->nodes[i].parentid == root_id) {
-                       if (!tree->nodes[i].dirname) {
-                               WARN("Odd condition: child objid with no name under %s\n", path);
-                               continue;
-                       }
-                       len = strlen(path) + strlen(tree->nodes[i].dirname) + 2;
-                       newpath = malloc(len);
-                       if (!newpath) {
-                               ERROR("Out of memory");
-                               return false;
-                       }
-                       snprintf(newpath, len, "%s/%s", path, tree->nodes[i].dirname);
-                       if (!do_remove_btrfs_children(tree, tree->nodes[i].objid, newpath)) {
-                               ERROR("Failed to prune %s\n", tree->nodes[i].name);
-                               free(newpath);
-                               return false;
-                       }
-                       if (btrfs_do_destroy_subvol(newpath) != 0) {
-                               ERROR("Failed to remove %s\n", newpath);
-                               free(newpath);
-                               return false;
-                       }
-                       free(newpath);
-               }
-       }
-       return true;
-}
-
-static int btrfs_recursive_destroy(const char *path)
-{
-       u64 root_id;
-       int fd;
-       struct btrfs_ioctl_search_args args;
-       struct btrfs_ioctl_search_key *sk = &args.key;
-       struct btrfs_ioctl_search_header *sh;
-       struct btrfs_root_ref *ref;
-       struct my_btrfs_tree *tree;
-       int ret, i;
-       unsigned long off = 0;
-       int name_len;
-       char *name;
-       char *tmppath;
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               ERROR("Failed to open %s\n", path);
-               return -1;
-       }
-
-       if (btrfs_list_get_path_rootid(fd, &root_id)) {
-               close(fd);
-               if (errno == EPERM || errno == EACCES) {
-                       WARN("Will simply try removing");
-                       goto ignore_search;
-               }
-
-               return -1;
-       }
-
-       tree = create_my_btrfs_tree(root_id, path, strlen(path));
-       if (!tree) {
-               ERROR("Out of memory\n");
-               close(fd);
-               return -1;
-       }
-       /* Walk all subvols looking for any under this id */
-       memset(&args, 0, sizeof(args));
-
-       /* search in the tree of tree roots */
-       sk->tree_id = 1;
-
-       sk->max_type = BTRFS_ROOT_REF_KEY;
-       sk->min_type = BTRFS_ROOT_ITEM_KEY;
-       sk->min_objectid = 0;
-       sk->max_objectid = (u64)-1;
-       sk->max_offset = (u64)-1;
-       sk->min_offset = 0;
-       sk->max_transid = (u64)-1;
-       sk->nr_items = 4096;
-
-       while(1) {
-               ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-               if (ret < 0) {
-                       close(fd);
-                       ERROR("Error: can't perform the search under %s\n", path);
-                       free_btrfs_tree(tree);
-                       return -1;
-               }
-               if (sk->nr_items == 0)
-                       break;
-
-               off = 0;
-               for (i = 0; i < sk->nr_items; i++) {
-                       sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
-                       off += sizeof(*sh);
-                       /*
-                        * A backref key with the name and dirid of the parent
-                        * comes followed by the reoot ref key which has the
-                        * name of the child subvol in question.
-                        */
-                       if (sh->objectid != root_id && sh->type == BTRFS_ROOT_BACKREF_KEY) {
-                               ref = (struct btrfs_root_ref *)(args.buf + off);
-                               name_len = ref->name_len;
-                               name = (char *)(ref + 1);
-                               tmppath = get_btrfs_subvol_path(fd, sh->offset,
-                                               ref->dirid, name, name_len);
-                               if (!add_btrfs_tree_node(tree, sh->objectid,
-                                                       sh->offset, name,
-                                                       name_len, tmppath)) {
-                                       ERROR("Out of memory");
-                                       free_btrfs_tree(tree);
-                                       free(tmppath);
-                                       close(fd);
-                                       return -1;
-                               }
-                               free(tmppath);
-                       }
-                       off += sh->len;
-
-                       /*
-                        * record the mins in sk so we can make sure the
-                        * next search doesn't repeat this root
-                        */
-                       sk->min_objectid = sh->objectid;
-                       sk->min_type = sh->type;
-                       sk->min_offset = sh->offset;
-               }
-               sk->nr_items = 4096;
-               sk->min_offset++;
-               if (!sk->min_offset)
-                       sk->min_type++;
-               else
-                       continue;
-
-               if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) {
-                       sk->min_type = BTRFS_ROOT_ITEM_KEY;
-                       sk->min_objectid++;
-               } else
-                       continue;
-
-               if (sk->min_objectid >= sk->max_objectid)
-                       break;
-       }
-       close(fd);
-
-       /* now actually remove them */
-
-       if (!do_remove_btrfs_children(tree, root_id, path)) {
-               free_btrfs_tree(tree);
-               ERROR("failed pruning\n");
-               return -1;
-       }
-
-       free_btrfs_tree(tree);
-       /* All child subvols have been removed, now remove this one */
-ignore_search:
-       return btrfs_do_destroy_subvol(path);
-}
-
-bool btrfs_try_remove_subvol(const char *path)
-{
-       if (!btrfs_detect(path))
-               return false;
-       return btrfs_recursive_destroy(path) == 0;
-}
-
-static int btrfs_destroy(struct bdev *orig)
-{
-       return btrfs_recursive_destroy(orig->src);
-}
-
-static int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       bdev->src = strdup(dest);
-       bdev->dest = strdup(dest);
-       if (!bdev->src || !bdev->dest)
-               return -1;
-       return btrfs_subvolume_create(bdev->dest);
-}
-
-static const struct bdev_ops btrfs_ops = {
-       .detect = &btrfs_detect,
-       .mount = &btrfs_mount,
-       .umount = &btrfs_umount,
-       .clone_paths = &btrfs_clonepaths,
-       .destroy = &btrfs_destroy,
-       .create = &btrfs_create,
-       .can_snapshot = true,
-       .can_backup = true,
-};
-
-//
-// loopback dev ops
-//
-static int loop_detect(const char *path)
-{
-       if (strncmp(path, "loop:", 5) == 0)
-               return 1;
-       return 0;
-}
-
-static int find_free_loopdev_no_control(int *retfd, char *namep)
-{
-       struct dirent dirent, *direntp;
-       struct loop_info64 lo;
-       DIR *dir;
-       int fd = -1;
-
-       dir = opendir("/dev");
-       if (!dir) {
-               SYSERROR("Error opening /dev");
-               return -1;
-       }
-       while (!readdir_r(dir, &dirent, &direntp)) {
-
-               if (!direntp)
-                       break;
-               if (strncmp(direntp->d_name, "loop", 4) != 0)
-                       continue;
-               fd = openat(dirfd(dir), direntp->d_name, O_RDWR);
-               if (fd < 0)
-                       continue;
-               if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) {
-                       close(fd);
-                       fd = -1;
-                       continue;
-               }
-               // We can use this fd
-               snprintf(namep, 100, "/dev/%s", direntp->d_name);
-               break;
-       }
-       closedir(dir);
-       if (fd == -1) {
-               ERROR("No loop device found");
-               return -1;
-       }
-
-       *retfd = fd;
-       return 0;
-}
-
-static int find_free_loopdev(int *retfd, char *namep)
-{
-       int rc, fd = -1;
-       int ctl = open("/dev/loop-control", O_RDWR);
-       if (ctl < 0)
-               return find_free_loopdev_no_control(retfd, namep);
-       rc = ioctl(ctl, LOOP_CTL_GET_FREE);
-       if (rc >= 0) {
-               snprintf(namep, 100, "/dev/loop%d", rc);
-               fd = open(namep, O_RDWR);
-       }
-       close(ctl);
-       if (fd == -1) {
-               ERROR("No loop device found");
-               return -1;
-       }
-       *retfd = fd;
-       return 0;
-}
-
-static int loop_mount(struct bdev *bdev)
-{
-       int lfd, ffd = -1, ret = -1;
-       struct loop_info64 lo;
-       char loname[100];
-
-       if (strcmp(bdev->type, "loop"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       if (find_free_loopdev(&lfd, loname) < 0)
-               return -22;
-
-       ffd = open(bdev->src + 5, O_RDWR);
-       if (ffd < 0) {
-               SYSERROR("Error opening backing file %s", bdev->src);
-               goto out;
-       }
-
-       if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) {
-               SYSERROR("Error attaching backing file to loop dev");
-               goto out;
-       }
-       memset(&lo, 0, sizeof(lo));
-       lo.lo_flags = LO_FLAGS_AUTOCLEAR;
-       if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) {
-               SYSERROR("Error setting autoclear on loop dev");
-               goto out;
-       }
-
-       ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
-       if (ret < 0)
-               ERROR("Error mounting %s", bdev->src);
-       else
-               bdev->lofd = lfd;
-
-out:
-       if (ffd > -1)
-               close(ffd);
-       if (ret < 0) {
-               close(lfd);
-               bdev->lofd = -1;
-       }
-       return ret;
-}
-
-static int loop_umount(struct bdev *bdev)
-{
-       int ret;
-
-       if (strcmp(bdev->type, "loop"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       ret = umount(bdev->dest);
-       if (bdev->lofd >= 0) {
-               close(bdev->lofd);
-               bdev->lofd = -1;
-       }
-       return ret;
-}
-
-static int do_loop_create(const char *path, uint64_t size, const char *fstype)
-{
-       int fd, ret;
-       // create the new loopback file.
-       fd = creat(path, S_IRUSR|S_IWUSR);
-       if (fd < 0)
-               return -1;
-       if (lseek(fd, size, SEEK_SET) < 0) {
-               SYSERROR("Error seeking to set new loop file size");
-               close(fd);
-               return -1;
-       }
-       if (write(fd, "1", 1) != 1) {
-               SYSERROR("Error creating new loop file");
-               close(fd);
-               return -1;
-       }
-       ret = close(fd);
-       if (ret < 0) {
-               SYSERROR("Error closing new loop file");
-               return -1;
-       }
-
-       // create an fs in the loopback file
-       if (do_mkfs(path, fstype) < 0) {
-               ERROR("Error creating filesystem type %s on %s", fstype,
-                       path);
-               return -1;
-       }
-
-       return 0;
-}
-
-/*
- * No idea what the original blockdev will be called, but the copy will be
- * called $lxcpath/$lxcname/rootdev
- */
-static int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       char fstype[100];
-       uint64_t size = newsize;
-       int len, ret;
-       char *srcdev;
-
-       if (snap) {
-               ERROR("loop devices cannot be snapshotted.");
-               return -1;
-       }
-
-       if (!orig->dest || !orig->src)
-               return -1;
-
-       len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3;
-       srcdev = alloca(len);
-       ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-
-       new->src = malloc(len + 5);
-       if (!new->src)
-               return -1;
-       ret = snprintf(new->src, len + 5, "loop:%s", srcdev);
-       if (ret < 0 || ret >= len + 5)
-               return -1;
-
-       new->dest = malloc(len);
-       if (!new->dest)
-               return -1;
-       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-
-       // it's tempting to say: if orig->src == loopback and !newsize, then
-       // copy the loopback file.  However, we'd have to make sure to
-       // correctly keep holes!  So punt for now.
-
-       if (is_blktype(orig)) {
-               if (!newsize && blk_getsize(orig, &size) < 0) {
-                       ERROR("Error getting size of %s", orig->src);
-                       return -1;
-               }
-               if (detect_fs(orig, fstype, 100) < 0) {
-                       INFO("could not find fstype for %s, using %s", orig->src,
-                               DEFAULT_FSTYPE);
-                       return -1;
-               }
-       } else {
-               sprintf(fstype, "%s", DEFAULT_FSTYPE);
-               if (!newsize)
-                       size = DEFAULT_FS_SIZE;
-       }
-       return do_loop_create(srcdev, size, fstype);
-}
-
-static int loop_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       const char *fstype;
-       uint64_t sz;
-       int ret, len;
-       char *srcdev;
-
-       if (!specs)
-               return -1;
-
-       // dest is passed in as $lxcpath / $lxcname / rootfs
-       // srcdev will be:      $lxcpath / $lxcname / rootdev
-       // src will be 'loop:$srcdev'
-       len = strlen(dest) + 2;
-       srcdev = alloca(len);
-
-       ret = snprintf(srcdev, len, "%s", dest);
-       if (ret < 0 || ret >= len)
-               return -1;
-       sprintf(srcdev + len - 4, "dev");
-
-       bdev->src = malloc(len + 5);
-       if (!bdev->src)
-               return -1;
-       ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev);
-       if (ret < 0 || ret >= len + 5)
-               return -1;
-
-       sz = specs->fssize;
-       if (!sz)
-               sz = DEFAULT_FS_SIZE;
-
-       fstype = specs->fstype;
-       if (!fstype)
-               fstype = DEFAULT_FSTYPE;
-
-       if (!(bdev->dest = strdup(dest)))
-               return -1;
-
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
-               return -1;
-       }
-
-       return do_loop_create(srcdev, sz, fstype);
-}
-
-static int loop_destroy(struct bdev *orig)
-{
-       return unlink(orig->src + 5);
-}
-
-static const struct bdev_ops loop_ops = {
-       .detect = &loop_detect,
-       .mount = &loop_mount,
-       .umount = &loop_umount,
-       .clone_paths = &loop_clonepaths,
-       .destroy = &loop_destroy,
-       .create = &loop_create,
-       .can_snapshot = false,
-       .can_backup = true,
-};
-
-//
-// overlayfs ops
-//
-
-static int overlayfs_detect(const char *path)
-{
-       if (strncmp(path, "overlayfs:", 10) == 0)
-               return 1; // take their word for it
-       return 0;
-}
-
-static char *overlayfs_name;
-static char *detect_overlayfs_name(void)
-{
-       char *v = "overlayfs";
-       char *line = NULL;
-       size_t len = 0;
-       FILE *f = fopen("/proc/filesystems", "r");
-       if (!f)
-               return v;
-
-       while (getline(&line, &len, f) != -1) {
-               if (strcmp(line, "nodev\toverlay\n") == 0) {
-                       v = "overlay";
-                       break;
-               }
-       }
-
-       fclose(f);
-       free(line);
-       return v;
-}
-
-//
-// XXXXXXX plain directory bind mount ops
-//
-static int overlayfs_mount(struct bdev *bdev)
-{
-       char *options, *dup, *lower, *upper;
-       char *options_work, *work, *lastslash;
-       int lastslashidx;
-       int len, len2;
-       unsigned long mntflags;
-       char *mntdata;
-       int ret, ret2;
-
-       if (strcmp(bdev->type, "overlayfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       if (!overlayfs_name)
-               overlayfs_name = detect_overlayfs_name();
-
-       //  separately mount it first
-       //  mount -t overlayfs -oupperdir=${upper},lowerdir=${lower} lower dest
-       dup = alloca(strlen(bdev->src)+1);
-       strcpy(dup, bdev->src);
-       if (!(lower = strchr(dup, ':')))
-               return -22;
-       if (!(upper = strchr(++lower, ':')))
-               return -22;
-       *upper = '\0';
-       upper++;
-
-       // if delta doesn't yet exist, create it
-       if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
-               return -22;
-
-       // overlayfs.v22 or higher needs workdir option
-       // if upper is /var/lib/lxc/c2/delta0,
-       // then workdir is /var/lib/lxc/c2/olwork
-       lastslash = strrchr(upper, '/');
-       if (!lastslash)
-               return -22;
-       lastslash++;
-       lastslashidx = lastslash - upper;
-
-       work = alloca(lastslashidx + 7);
-       strncpy(work, upper, lastslashidx+7);
-       strcpy(work+lastslashidx, "olwork");
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
-               free(mntdata);
-               return -22;
-       }
-
-       // TODO We should check whether bdev->src is a blockdev, and if so
-       // but for now, only support overlays of a basic directory
-
-       if (mntdata) {
-               len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
-               options = alloca(len);
-               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
-
-               len2 = strlen(lower) + strlen(upper) + strlen(work)
-                       + strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
-               options_work = alloca(len2);
-               ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
-                               upper, lower, work, mntdata);
-       }
-       else {
-               len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
-               options = alloca(len);
-               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
-
-               len2 = strlen(lower) + strlen(upper) + strlen(work)
-                       + strlen("upperdir=,lowerdir=,workdir=") + 1;
-               options_work = alloca(len2);
-               ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
-                       upper, lower, work);
-       }
-       if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
-               free(mntdata);
-               return -1;
-       }
-
-       // mount without workdir option for overlayfs before v21
-       ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options);
-       if (ret < 0) {
-               INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
-                       lower, bdev->dest, options);
-
-               // retry with workdir option for overlayfs v22 and higher
-               ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options_work);
-               if (ret < 0)
-                       SYSERROR("overlayfs: error mounting %s onto %s options %s",
-                               lower, bdev->dest, options_work);
-               else
-                       INFO("overlayfs: mounted %s onto %s options %s",
-                               lower, bdev->dest, options_work);
-       }
-       else
-               INFO("overlayfs: mounted %s onto %s options %s",
-                       lower, bdev->dest, options);
-       return ret;
-}
-
-static int overlayfs_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "overlayfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int rsync_delta(struct rsync_data_char *data)
-{
-       if (setgid(0) < 0) {
-               ERROR("Failed to setgid to 0");
-               return -1;
-       }
-       if (setgroups(0, NULL) < 0)
-               WARN("Failed to clear groups");
-       if (setuid(0) < 0) {
-               ERROR("Failed to setuid to 0");
-               return -1;
-       }
-       if (do_rsync(data->src, data->dest) < 0) {
-               ERROR("rsyncing %s to %s", data->src, data->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int rsync_delta_wrapper(void *data)
-{
-       struct rsync_data_char *arg = data;
-       return rsync_delta(arg);
-}
-
-static int ovl_rsync(struct ovl_rsync_data *data)
-{
-       int ret;
-
-       if (setgid(0) < 0) {
-               ERROR("Failed to setgid to 0");
-               return -1;
-       }
-       if (setgroups(0, NULL) < 0)
-               WARN("Failed to clear groups");
-       if (setuid(0) < 0) {
-               ERROR("Failed to setuid to 0");
-               return -1;
-       }
-
-       if (unshare(CLONE_NEWNS) < 0) {
-               SYSERROR("Unable to unshare mounts ns");
-               return -1;
-       }
-       if (detect_shared_rootfs()) {
-               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
-                       SYSERROR("Failed to make / rslave");
-                       ERROR("Continuing...");
-               }
-       }
-       if (overlayfs_mount(data->orig) < 0) {
-               ERROR("Failed mounting original container fs");
-               return -1;
-       }
-       if (overlayfs_mount(data->new) < 0) {
-               ERROR("Failed mounting new container fs");
-               return -1;
-       }
-       ret = do_rsync(data->orig->dest, data->new->dest);
-
-       overlayfs_umount(data->new);
-       overlayfs_umount(data->orig);
-
-       if (ret < 0) {
-               ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int ovl_rsync_wrapper(void *data)
-{
-       struct ovl_rsync_data *arg = data;
-       return ovl_rsync(arg);
-}
-
-static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
-{
-       int ret = -1;
-       struct ovl_rsync_data rdata;
-
-       rdata.orig = orig;
-       rdata.new = new;
-       if (am_unpriv())
-               ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
-       else
-               ret = ovl_rsync(&rdata);
-       if (ret)
-               ERROR("copying overlayfs delta");
-
-       return ret;
-}
-
-static int overlayfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       if (!snap) {
-               ERROR("overlayfs is only for snapshot clones");
-               return -22;
-       }
-
-       if (!orig->src || !orig->dest)
-               return -1;
-
-       new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
-       if (!new->dest)
-               return -1;
-       if (mkdir_p(new->dest, 0755) < 0)
-               return -1;
-
-       if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
-               WARN("Failed to update ownership of %s", new->dest);
-
-       if (strcmp(orig->type, "dir") == 0) {
-               char *delta, *lastslash;
-               char *work;
-               int ret, len, lastslashidx;
-
-               // if we have /var/lib/lxc/c2/rootfs, then delta will be
-               //            /var/lib/lxc/c2/delta0
-               lastslash = strrchr(new->dest, '/');
-               if (!lastslash)
-                       return -22;
-               if (strlen(lastslash) < 7)
-                       return -22;
-               lastslash++;
-               lastslashidx = lastslash - new->dest;
-
-               delta = malloc(lastslashidx + 7);
-               if (!delta)
-                       return -1;
-               strncpy(delta, new->dest, lastslashidx+1);
-               strcpy(delta+lastslashidx, "delta0");
-               if ((ret = mkdir(delta, 0755)) < 0) {
-                       SYSERROR("error: mkdir %s", delta);
-                       free(delta);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
-                       WARN("Failed to update ownership of %s", delta);
-
-               // make workdir for overlayfs.v22 or higher
-               // workdir is /var/lib/lxc/c2/olwork
-               // it is used to prepare files before atomically swithing with destination,
-               // and needs to be on the same filesystem as upperdir,
-               // so it's OK for it to be empty.
-               work = malloc(lastslashidx + 7);
-               if (!work) {
-                       free(delta);
-                       return -1;
-               }
-               strncpy(work, new->dest, lastslashidx+1);
-               strcpy(work+lastslashidx, "olwork");
-               if (mkdir(work, 0755) < 0) {
-                       SYSERROR("error: mkdir %s", work);
-                       free(delta);
-                       free(work);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
-                       WARN("Failed to update ownership of %s", work);
-               free(work);
-
-               // the src will be 'overlayfs:lowerdir:upperdir'
-               len = strlen(delta) + strlen(orig->src) + 12;
-               new->src = malloc(len);
-               if (!new->src) {
-                       free(delta);
-                       return -ENOMEM;
-               }
-               ret = snprintf(new->src, len, "overlayfs:%s:%s", orig->src, delta);
-               free(delta);
-               if (ret < 0 || ret >= len)
-                       return -ENOMEM;
-       } else if (strcmp(orig->type, "overlayfs") == 0) {
-               // What exactly do we want to do here?
-               // I think we want to use the original lowerdir, with a
-               // private delta which is originally rsynced from the
-               // original delta
-               char *osrc, *odelta, *nsrc, *ndelta, *work;
-               char *lastslash;
-               int len, ret, lastslashidx;
-               if (!(osrc = strdup(orig->src)))
-                       return -22;
-               nsrc = strchr(osrc, ':') + 1;
-               if (nsrc != osrc + 10 || (odelta = strchr(nsrc, ':')) == NULL) {
-                       free(osrc);
-                       return -22;
-               }
-               *odelta = '\0';
-               odelta++;
-               ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
-               if (!ndelta) {
-                       free(osrc);
-                       return -ENOMEM;
-               }
-               if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
-                       SYSERROR("error: mkdir %s", ndelta);
-                       free(osrc);
-                       free(ndelta);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
-                       WARN("Failed to update ownership of %s", ndelta);
-
-               // make workdir for overlayfs.v22 or higher
-               // for details, see above.
-               lastslash = strrchr(ndelta, '/');
-               if (!lastslash)
-                       return -1;
-               lastslash++;
-               lastslashidx = lastslash - ndelta;
-
-               work = malloc(lastslashidx + 7);
-               if (!work)
-                       return -1;
-               strncpy(work, ndelta, lastslashidx+1);
-               strcpy(work+lastslashidx, "olwork");
-               if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
-                       SYSERROR("error: mkdir %s", work);
-                       free(work);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
-                       WARN("Failed to update ownership of %s", work);
-               free(work);
-
-               len = strlen(nsrc) + strlen(ndelta) + 12;
-               new->src = malloc(len);
-               if (!new->src) {
-                       free(osrc);
-                       free(ndelta);
-                       return -ENOMEM;
-               }
-               ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
-               free(osrc);
-               free(ndelta);
-               if (ret < 0 || ret >= len)
-                       return -ENOMEM;
-
-               return ovl_do_rsync(orig, new, conf);
-       } else {
-               ERROR("overlayfs clone of %s container is not yet supported",
-                       orig->type);
-               // Note, supporting this will require overlayfs_mount supporting
-               // mounting of the underlay.  No big deal, just needs to be done.
-               return -1;
-       }
-
-       return 0;
-}
-
-static int overlayfs_destroy(struct bdev *orig)
-{
-       char *upper;
-
-       if (strncmp(orig->src, "overlayfs:", 10) != 0)
-               return -22;
-       upper = strchr(orig->src + 10, ':');
-       if (!upper)
-               return -22;
-       upper++;
-       return lxc_rmdir_onedev(upper, NULL);
-}
-
-/*
- * to say 'lxc-create -t ubuntu -n o1 -B overlayfs' means you want
- * $lxcpath/$lxcname/rootfs to have the created container, while all
- * changes after starting the container are written to
- * $lxcpath/$lxcname/delta0
- */
-static int overlayfs_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       char *delta;
-       int ret, len = strlen(dest), newlen;
-
-       if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
-               return -1;
-
-       if (!(bdev->dest = strdup(dest))) {
-               ERROR("Out of memory");
-               return -1;
-       }
-
-       delta = alloca(strlen(dest)+1);
-       strcpy(delta, dest);
-       strcpy(delta+len-6, "delta0");
-
-       if (mkdir_p(delta, 0755) < 0) {
-               ERROR("Error creating %s", delta);
-               return -1;
-       }
-
-       /* overlayfs:lower:upper */
-       newlen = (2 * len) + strlen("overlayfs:") + 2;
-       bdev->src = malloc(newlen);
-       if (!bdev->src) {
-               ERROR("Out of memory");
-               return -1;
-       }
-       ret = snprintf(bdev->src, newlen, "overlayfs:%s:%s", dest, delta);
-       if (ret < 0 || ret >= newlen)
-               return -1;
-
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static const struct bdev_ops overlayfs_ops = {
-       .detect = &overlayfs_detect,
-       .mount = &overlayfs_mount,
-       .umount = &overlayfs_umount,
-       .clone_paths = &overlayfs_clonepaths,
-       .destroy = &overlayfs_destroy,
-       .create = &overlayfs_create,
-       .can_snapshot = true,
-       .can_backup = true,
-};
-
-//
-// aufs ops
-//
-
-static int aufs_detect(const char *path)
-{
-       if (strncmp(path, "aufs:", 5) == 0)
-               return 1; // take their word for it
-       return 0;
-}
-
-//
-// XXXXXXX plain directory bind mount ops
-//
-static int aufs_mount(struct bdev *bdev)
-{
-       char *options, *dup, *lower, *upper;
-       int len;
-       unsigned long mntflags;
-       char *mntdata;
-       int ret;
-       const char *xinopath = "/dev/shm/aufs.xino";
-
-       if (strcmp(bdev->type, "aufs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       //  separately mount it first
-       //  mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest
-       dup = alloca(strlen(bdev->src)+1);
-       strcpy(dup, bdev->src);
-       if (!(lower = strchr(dup, ':')))
-               return -22;
-       if (!(upper = strchr(++lower, ':')))
-               return -22;
-       *upper = '\0';
-       upper++;
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       // TODO We should check whether bdev->src is a blockdev, and if so
-       // but for now, only support aufs of a basic directory
-
-       // AUFS does not work on top of certain filesystems like (XFS or Btrfs)
-       // so add xino=/dev/shm/aufs.xino parameter to mount options.
-       // The same xino option can be specified to multiple aufs mounts, and
-       // a xino file is not shared among multiple aufs mounts.
-       //
-       // see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
-       //     http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
-       if (mntdata) {
-               len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
-               options = alloca(len);
-               ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
-       }
-       else {
-               len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
-               options = alloca(len);
-               ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
-       }
-
-       if (ret < 0 || ret >= len) {
-               free(mntdata);
-               return -1;
-       }
-
-       ret = mount(lower, bdev->dest, "aufs", MS_MGC_VAL | mntflags, options);
-       if (ret < 0)
-               SYSERROR("aufs: error mounting %s onto %s options %s",
-                       lower, bdev->dest, options);
-       else
-               INFO("aufs: mounted %s onto %s options %s",
-                       lower, bdev->dest, options);
-       return ret;
-}
-
-static int aufs_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "aufs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int aufs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       if (!snap) {
-               ERROR("aufs is only for snapshot clones");
-               return -22;
-       }
-
-       if (!orig->src || !orig->dest)
-               return -1;
-
-       new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
-       if (!new->dest)
-               return -1;
-       if (mkdir_p(new->dest, 0755) < 0)
-               return -1;
-
-       if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
-               WARN("Failed to update ownership of %s", new->dest);
-
-       if (strcmp(orig->type, "dir") == 0) {
-               char *delta, *lastslash;
-               int ret, len, lastslashidx;
-
-               // if we have /var/lib/lxc/c2/rootfs, then delta will be
-               //            /var/lib/lxc/c2/delta0
-               lastslash = strrchr(new->dest, '/');
-               if (!lastslash)
-                       return -22;
-               if (strlen(lastslash) < 7)
-                       return -22;
-               lastslash++;
-               lastslashidx = lastslash - new->dest;
-
-               delta = malloc(lastslashidx + 7);
-               if (!delta)
-                       return -1;
-               strncpy(delta, new->dest, lastslashidx+1);
-               strcpy(delta+lastslashidx, "delta0");
-               if ((ret = mkdir(delta, 0755)) < 0) {
-                       SYSERROR("error: mkdir %s", delta);
-                       free(delta);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
-                       WARN("Failed to update ownership of %s", delta);
-
-               // the src will be 'aufs:lowerdir:upperdir'
-               len = strlen(delta) + strlen(orig->src) + 12;
-               new->src = malloc(len);
-               if (!new->src) {
-                       free(delta);
-                       return -ENOMEM;
-               }
-               ret = snprintf(new->src, len, "aufs:%s:%s", orig->src, delta);
-               free(delta);
-               if (ret < 0 || ret >= len)
-                       return -ENOMEM;
-       } else if (strcmp(orig->type, "aufs") == 0) {
-               // What exactly do we want to do here?
-               // I think we want to use the original lowerdir, with a
-               // private delta which is originally rsynced from the
-               // original delta
-               char *osrc, *odelta, *nsrc, *ndelta;
-               int len, ret;
-               if (!(osrc = strdup(orig->src)))
-                       return -22;
-               nsrc = strchr(osrc, ':') + 1;
-               if (nsrc != osrc + 5 || (odelta = strchr(nsrc, ':')) == NULL) {
-                       free(osrc);
-                       return -22;
-               }
-               *odelta = '\0';
-               odelta++;
-               ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
-               if (!ndelta) {
-                       free(osrc);
-                       return -ENOMEM;
-               }
-               if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
-                       SYSERROR("error: mkdir %s", ndelta);
-                       free(osrc);
-                       free(ndelta);
-                       return -1;
-               }
-               if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
-                       WARN("Failed to update ownership of %s", ndelta);
-
-               struct rsync_data_char rdata;
-               rdata.src = odelta;
-               rdata.dest = ndelta;
-               if (am_unpriv())
-                       ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata);
-               else
-                       ret = rsync_delta(&rdata);
-               if (ret) {
-                       free(osrc);
-                       free(ndelta);
-                       ERROR("copying aufs delta");
-                       return -1;
-               }
-               len = strlen(nsrc) + strlen(ndelta) + 12;
-               new->src = malloc(len);
-               if (!new->src) {
-                       free(osrc);
-                       free(ndelta);
-                       return -ENOMEM;
-               }
-               ret = snprintf(new->src, len, "aufs:%s:%s", nsrc, ndelta);
-               free(osrc);
-               free(ndelta);
-               if (ret < 0 || ret >= len)
-                       return -ENOMEM;
-       } else {
-               ERROR("aufs clone of %s container is not yet supported",
-                       orig->type);
-               // Note, supporting this will require aufs_mount supporting
-               // mounting of the underlay.  No big deal, just needs to be done.
-               return -1;
-       }
-
-       return 0;
-}
-
-static int aufs_destroy(struct bdev *orig)
-{
-       char *upper;
-
-       if (strncmp(orig->src, "aufs:", 5) != 0)
-               return -22;
-       upper = strchr(orig->src + 5, ':');
-       if (!upper)
-               return -22;
-       upper++;
-       return lxc_rmdir_onedev(upper, NULL);
-}
-
-/*
- * to say 'lxc-create -t ubuntu -n o1 -B aufs' means you want
- * $lxcpath/$lxcname/rootfs to have the created container, while all
- * changes after starting the container are written to
- * $lxcpath/$lxcname/delta0
- */
-static int aufs_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       char *delta;
-       int ret, len = strlen(dest), newlen;
-
-       if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
-               return -1;
-
-       if (!(bdev->dest = strdup(dest))) {
-               ERROR("Out of memory");
-               return -1;
-       }
-
-       delta = alloca(strlen(dest)+1);
-       strcpy(delta, dest);
-       strcpy(delta+len-6, "delta0");
-
-       if (mkdir_p(delta, 0755) < 0) {
-               ERROR("Error creating %s", delta);
-               return -1;
-       }
-
-       /* aufs:lower:upper */
-       newlen = (2 * len) + strlen("aufs:") + 2;
-       bdev->src = malloc(newlen);
-       if (!bdev->src) {
-               ERROR("Out of memory");
-               return -1;
-       }
-       ret = snprintf(bdev->src, newlen, "aufs:%s:%s", dest, delta);
-       if (ret < 0 || ret >= newlen)
-               return -1;
-
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-static const struct bdev_ops aufs_ops = {
-       .detect = &aufs_detect,
-       .mount = &aufs_mount,
-       .umount = &aufs_umount,
-       .clone_paths = &aufs_clonepaths,
-       .destroy = &aufs_destroy,
-       .create = &aufs_create,
-       .can_snapshot = true,
-       .can_backup = true,
-};
-
-//
-// nbd dev ops
-//
-
-static int nbd_detect(const char *path)
-{
-       if (strncmp(path, "nbd:", 4) == 0)
-               return 1;
-       return 0;
-}
-
-struct nbd_attach_data {
-       const char *nbd;
-       const char *path;
-};
-
-static void nbd_detach(const char *path)
-{
-       int ret;
-       pid_t pid = fork();
-
-       if (pid < 0) {
-               SYSERROR("Error forking to detach nbd");
-               return;
-       }
-       if (pid) {
-               ret = wait_for_pid(pid);
-               if (ret < 0)
-                       ERROR("nbd disconnect returned an error");
-               return;
-       }
-       execlp("qemu-nbd", "qemu-nbd", "-d", path, NULL);
-       SYSERROR("Error executing qemu-nbd");
-       exit(1);
-}
-
-static int do_attach_nbd(void *d)
-{
-       struct nbd_attach_data *data = d;
-       const char *nbd, *path;
-       pid_t pid;
-       sigset_t mask;
-       int sfd;
-       ssize_t s;
-       struct signalfd_siginfo fdsi;
-
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGHUP);
-       sigaddset(&mask, SIGCHLD);
-
-       nbd = data->nbd;
-       path = data->path;
-
-       if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
-               SYSERROR("Error blocking signals for nbd watcher");
-               exit(1);
-       }
-
-       sfd = signalfd(-1, &mask, 0);
-       if (sfd == -1) {
-               SYSERROR("Error opening signalfd for nbd task");
-               exit(1);
-       }
-
-       if (prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0) < 0)
-               SYSERROR("Error setting parent death signal for nbd watcher");
-
-       pid = fork();
-       if (pid) {
-               for (;;) {
-                       s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
-                       if (s != sizeof(struct signalfd_siginfo))
-                               SYSERROR("Error reading from signalfd");
-
-                       if (fdsi.ssi_signo == SIGHUP) {
-                               /* container has exited */
-                               nbd_detach(nbd);
-                               exit(0);
-                       } else if (fdsi.ssi_signo == SIGCHLD) {
-                               int status;
-                               /* If qemu-nbd fails, or is killed by a signal,
-                                * then exit */
-                               while (waitpid(-1, &status, WNOHANG) > 0) {
-                                       if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) ||
-                                                       WIFSIGNALED(status)) {
-                                               nbd_detach(nbd);
-                                               exit(1);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       close(sfd);
-       if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
-               WARN("Warning: unblocking signals for nbd watcher");
-
-       execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, NULL);
-       SYSERROR("Error executing qemu-nbd");
-       exit(1);
-}
-
-static bool clone_attach_nbd(const char *nbd, const char *path)
-{
-       pid_t pid;
-       struct nbd_attach_data data;
-
-       data.nbd = nbd;
-       data.path = path;
-
-       pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
-       if (pid < 0)
-               return false;
-       return true;
-}
-
-static bool nbd_busy(int idx)
-{
-       char path[100];
-       int ret;
-
-       ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);
-       if (ret < 0 || ret >= 100)
-               return true;
-       return file_exists(path);
-}
-
-static bool attach_nbd(char *src, struct lxc_conf *conf)
-{
-       char *orig = alloca(strlen(src)+1), *p, path[50];
-       int i = 0;
-
-       strcpy(orig, src);
-       /* if path is followed by a partition, drop that for now */
-       p = strchr(orig, ':');
-       if (p)
-               *p = '\0';
-       while (1) {
-               sprintf(path, "/dev/nbd%d", i);
-               if (!file_exists(path))
-                       return false;
-               if (nbd_busy(i)) {
-                       i++;
-                       continue;
-               }
-               if (!clone_attach_nbd(path, orig))
-                       return false;
-               conf->nbd_idx = i;
-               return true;
-       }
-}
-
-static bool requires_nbd(const char *path)
-{
-       if (strncmp(path, "nbd:", 4) == 0)
-               return true;
-       return false;
-}
-
-/*
- * attach_block_device returns true if all went well,
- * meaning either a block device was attached or was not
- * needed.  It returns false if something went wrong and
- * container startup should be stopped.
- */
-bool attach_block_device(struct lxc_conf *conf)
-{
-       char *path;
-
-       if (!conf->rootfs.path)
-               return true;
-       path = conf->rootfs.path;
-       if (!requires_nbd(path))
-               return true;
-       path = strchr(path, ':');
-       if (!path)
-               return false;
-       path++;
-       if (!attach_nbd(path, conf))
-               return false;
-       return true;
-}
-
-void detach_nbd_idx(int idx)
-{
-       int ret;
-       char path[50];
-
-       ret = snprintf(path, 50, "/dev/nbd%d", idx);
-       if (ret < 0 || ret >= 50)
-               return;
-
-       nbd_detach(path);
-}
-
-void detach_block_device(struct lxc_conf *conf)
-{
-       if (conf->nbd_idx != -1)
-               detach_nbd_idx(conf->nbd_idx);
-}
-
-/*
- * Pick the partition # off the end of a nbd:file:p
- * description.  Return 1-9 for the partition id, or 0
- * for no partition.
- */
-static int nbd_get_partition(const char *src)
-{
-       char *p = strchr(src, ':');
-       if (!p)
-               return 0;
-       p = strchr(p+1, ':');
-       if (!p)
-               return 0;
-       p++;
-       if (*p < '1' || *p > '9')
-               return 0;
-       return *p - '0';
-}
-
-static bool wait_for_partition(const char *path)
-{
-       int count = 0;
-       while (count < 5) {
-               if (file_exists(path))
-                       return true;
-               sleep(1);
-               count++;
-       }
-       ERROR("Device %s did not show up after 5 seconds", path);
-       return false;
-}
-
-static int nbd_mount(struct bdev *bdev)
-{
-       int ret = -1, partition;
-       char path[50];
-
-       if (strcmp(bdev->type, "nbd"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       /* nbd_idx should have been copied by bdev_init from the lxc_conf */
-       if (bdev->nbd_idx < 0)
-               return -22;
-       partition = nbd_get_partition(bdev->src);
-       if (partition)
-               ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
-                               partition);
-       else
-               ret = snprintf(path, 50, "/dev/nbd%d", bdev->nbd_idx);
-       if (ret < 0 || ret >= 50) {
-               ERROR("Error setting up nbd device path");
-               return ret;
-       }
-
-       /* It might take awhile for the partition files to show up */
-       if (partition) {
-               if (!wait_for_partition(path))
-                       return -2;
-       }
-       ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);
-       if (ret < 0)
-               ERROR("Error mounting %s", bdev->src);
-
-       return ret;
-}
-
-static int nbd_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       return -ENOSYS;
-}
-
-static int nbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
-               const char *cname, const char *oldpath, const char *lxcpath, int snap,
-               uint64_t newsize, struct lxc_conf *conf)
-{
-       return -ENOSYS;
-}
-
-static int nbd_destroy(struct bdev *orig)
-{
-       return -ENOSYS;
-}
-
-static int nbd_umount(struct bdev *bdev)
-{
-       int ret;
-
-       if (strcmp(bdev->type, "nbd"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       ret = umount(bdev->dest);
-       return ret;
-}
-
-static const struct bdev_ops nbd_ops = {
-       .detect = &nbd_detect,
-       .mount = &nbd_mount,
-       .umount = &nbd_umount,
-       .clone_paths = &nbd_clonepaths,
-       .destroy = &nbd_destroy,
-       .create = &nbd_create,
-       .can_snapshot = true,
-       .can_backup = false,
-};
-
-static const struct bdev_type bdevs[] = {
-       {.name = "zfs", .ops = &zfs_ops,},
-       {.name = "lvm", .ops = &lvm_ops,},
-       {.name = "btrfs", .ops = &btrfs_ops,},
-       {.name = "dir", .ops = &dir_ops,},
-       {.name = "aufs", .ops = &aufs_ops,},
-       {.name = "overlayfs", .ops = &overlayfs_ops,},
-       {.name = "loop", .ops = &loop_ops,},
-       {.name = "nbd", .ops = &nbd_ops,},
-};
-
-static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type);
-
-void bdev_put(struct bdev *bdev)
-{
-       free(bdev->mntopts);
-       free(bdev->src);
-       free(bdev->dest);
-       free(bdev);
-}
-
-struct bdev *bdev_get(const char *type)
-{
-       int i;
-       struct bdev *bdev;
-
-       for (i=0; i<numbdevs; i++) {
-               if (strcmp(bdevs[i].name, type) == 0)
-                       break;
-       }
-       if (i == numbdevs)
-               return NULL;
-       bdev = malloc(sizeof(struct bdev));
-       if (!bdev)
-               return NULL;
-       memset(bdev, 0, sizeof(struct bdev));
-       bdev->ops = bdevs[i].ops;
-       bdev->type = bdevs[i].name;
-       return bdev;
-}
-
-static const struct bdev_type *bdev_query(const char *src)
-{
-       int i;
-       for (i=0; i<numbdevs; i++) {
-               int r;
-               r = bdevs[i].ops->detect(src);
-               if (r)
-                       break;
-       }
-
-       if (i == numbdevs)
-               return NULL;
-       return &bdevs[i];
-}
-
-struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, const char *mntopts)
-{
-       struct bdev *bdev;
-       const struct bdev_type *q;
-
-       if (!src)
-               src = conf->rootfs.path;
-
-       if (!src)
-               return NULL;
-
-       q = bdev_query(src);
-       if (!q)
-               return NULL;
-
-       bdev = malloc(sizeof(struct bdev));
-       if (!bdev)
-               return NULL;
-       memset(bdev, 0, sizeof(struct bdev));
-       bdev->ops = q->ops;
-       bdev->type = q->name;
-       if (mntopts)
-               bdev->mntopts = strdup(mntopts);
-       if (src)
-               bdev->src = strdup(src);
-       if (dst)
-               bdev->dest = strdup(dst);
-       if (strcmp(bdev->type, "nbd") == 0)
-               bdev->nbd_idx = conf->nbd_idx;
-
-       return bdev;
-}
-
-struct rsync_data {
-       struct bdev *orig;
-       struct bdev *new;
-};
-
-static int rsync_rootfs(struct rsync_data *data)
-{
-       struct bdev *orig = data->orig,
-                   *new = data->new;
-
-       if (unshare(CLONE_NEWNS) < 0) {
-               SYSERROR("unshare CLONE_NEWNS");
-               return -1;
-       }
-       if (detect_shared_rootfs()) {
-               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
-                       SYSERROR("Failed to make / rslave");
-                       ERROR("Continuing...");
-               }
-       }
-
-       // If not a snapshot, copy the fs.
-       if (orig->ops->mount(orig) < 0) {
-               ERROR("failed mounting %s onto %s", orig->src, orig->dest);
-               return -1;
-       }
-       if (new->ops->mount(new) < 0) {
-               ERROR("failed mounting %s onto %s", new->src, new->dest);
-               return -1;
-       }
-       if (setgid(0) < 0) {
-               ERROR("Failed to setgid to 0");
-               return -1;
-       }
-       if (setgroups(0, NULL) < 0)
-               WARN("Failed to clear groups");
-       if (setuid(0) < 0) {
-               ERROR("Failed to setuid to 0");
-               return -1;
-       }
-       if (do_rsync(orig->dest, new->dest) < 0) {
-               ERROR("rsyncing %s to %s", orig->src, new->src);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int rsync_rootfs_wrapper(void *data)
-{
-       struct rsync_data *arg = data;
-       return rsync_rootfs(arg);
-}
-
-bool bdev_is_dir(struct lxc_conf *conf, const char *path)
-{
-       struct bdev *orig = bdev_init(conf, path, NULL, NULL);
-       bool ret = false;
-       if (!orig)
-               return ret;
-       if (strcmp(orig->type, "dir") == 0)
-               ret = true;
-       bdev_put(orig);
-       return ret;
-}
-
-bool bdev_can_backup(struct lxc_conf *conf)
-{
-       struct bdev *bdev = bdev_init(conf, NULL, NULL, NULL);
-       bool ret;
-
-       if (!bdev)
-               return false;
-       ret = bdev->ops->can_backup;
-       bdev_put(bdev);
-       return ret;
-}
-
-/*
- * is an unprivileged user allowed to make this kind of snapshot
- */
-static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
-               bool maybesnap)
-{
-       if (!t) {
-               // new type will be same as original
-               // (unless snap && b->type == dir, in which case it will be
-               // overlayfs -- which is also allowed)
-               if (strcmp(b->type, "dir") == 0 ||
-                               strcmp(b->type, "aufs") == 0 ||
-                               strcmp(b->type, "overlayfs") == 0 ||
-                               strcmp(b->type, "btrfs") == 0 ||
-                               strcmp(b->type, "loop") == 0)
-                       return true;
-               return false;
-       }
-
-       // unprivileged users can copy and snapshot dir, overlayfs,
-       // and loop.  In particular, not zfs, btrfs, or lvm.
-       if (strcmp(t, "dir") == 0 ||
-               strcmp(t, "aufs") == 0 ||
-               strcmp(t, "overlayfs") == 0 ||
-               strcmp(t, "btrfs") == 0 ||
-               strcmp(t, "loop") == 0)
-               return true;
-       return false;
-}
-
-/*
- * If we're not snaphotting, then bdev_copy becomes a simple case of mount
- * the original, mount the new, and rsync the contents.
- */
-struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
-                       const char *lxcpath, const char *bdevtype,
-                       int flags, const char *bdevdata, uint64_t newsize,
-                       int *needs_rdep)
-{
-       struct bdev *orig, *new;
-       pid_t pid;
-       int ret;
-       bool snap = flags & LXC_CLONE_SNAPSHOT;
-       bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT;
-       bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE;
-       const char *src = c0->lxc_conf->rootfs.path;
-       const char *oldname = c0->name;
-       const char *oldpath = c0->config_path;
-       struct rsync_data data;
-
-       /* if the container name doesn't show up in the rootfs path, then
-        * we don't know how to come up with a new name
-        */
-       if (strstr(src, oldname) == NULL) {
-               ERROR("original rootfs path %s doesn't include container name %s",
-                       src, oldname);
-               return NULL;
-       }
-
-       orig = bdev_init(c0->lxc_conf, src, NULL, NULL);
-       if (!orig) {
-               ERROR("failed to detect blockdev type for %s", src);
-               return NULL;
-       }
-
-       if (!orig->dest) {
-               int ret;
-               size_t len;
-               struct stat sb;
-
-               len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2;
-               orig->dest = malloc(len);
-               if (!orig->dest) {
-                       ERROR("out of memory");
-                       bdev_put(orig);
-                       return NULL;
-               }
-               ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
-               if (ret < 0 || ret >= len) {
-                       ERROR("rootfs path too long");
-                       bdev_put(orig);
-                       return NULL;
-               }
-               ret = stat(orig->dest, &sb);
-               if (ret < 0 && errno == ENOENT)
-                       if (mkdir_p(orig->dest, 0755) < 0)
-                               WARN("Error creating '%s', continuing.", orig->dest);
-       }
-
-       /*
-        * special case for snapshot - if caller requested maybe_snapshot and
-        * keepbdevtype and backing store is directory, then proceed with a copy
-        * clone rather than returning error
-        */
-       if (maybe_snap && keepbdevtype && !bdevtype && !orig->ops->can_snapshot)
-               snap = false;
-
-       /*
-        * If newtype is NULL and snapshot is set, then use overlayfs
-        */
-       if (!bdevtype && !keepbdevtype && snap && strcmp(orig->type , "dir") == 0)
-               bdevtype = "overlayfs";
-
-       if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
-               ERROR("Unsupported snapshot type for unprivileged users");
-               bdev_put(orig);
-               return NULL;
-       }
-
-       *needs_rdep = 0;
-       if (bdevtype && strcmp(orig->type, "dir") == 0 &&
-                       (strcmp(bdevtype, "aufs") == 0 ||
-                        strcmp(bdevtype, "overlayfs") == 0)) {
-               *needs_rdep = 1;
-       } else if (snap && strcmp(orig->type, "lvm") == 0 &&
-                       !lvm_is_thin_volume(orig->src)) {
-               *needs_rdep = 1;
-       }
-
-       new = bdev_get(bdevtype ? bdevtype : orig->type);
-       if (!new) {
-               ERROR("no such block device type: %s", bdevtype ? bdevtype : orig->type);
-               bdev_put(orig);
-               return NULL;
-       }
-
-       if (new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
-                               snap, newsize, c0->lxc_conf) < 0) {
-               ERROR("failed getting pathnames for cloned storage: %s", src);
-               goto err;
-       }
-
-       if (am_unpriv() && chown_mapped_root(new->src, c0->lxc_conf) < 0)
-               WARN("Failed to update ownership of %s", new->dest);
-
-       if (snap)
-               return new;
-
-       /*
-        * https://github.com/lxc/lxc/issues/131
-        * Use btrfs snapshot feature instead of rsync to restore if both orig and new are btrfs
-        */
-       if (bdevtype &&
-                       strcmp(orig->type, "btrfs") == 0 && strcmp(new->type, "btrfs") == 0 &&
-                       btrfs_same_fs(orig->dest, new->dest) == 0) {
-               if (btrfs_destroy(new) < 0) {
-                       ERROR("Error destroying %s subvolume", new->dest);
-                       goto err;
-               }
-               if (mkdir_p(new->dest, 0755) < 0) {
-                       ERROR("Error creating %s directory", new->dest);
-                       goto err;
-               }
-               if (btrfs_snapshot(orig->dest, new->dest) < 0) {
-                       ERROR("Error restoring %s to %s", orig->dest, new->dest);
-                       goto err;
-               }
-               bdev_put(orig);
-               return new;
-       }
-
-       pid = fork();
-       if (pid < 0) {
-               SYSERROR("fork");
-               goto err;
-       }
-
-       if (pid > 0) {
-               int ret = wait_for_pid(pid);
-               bdev_put(orig);
-               if (ret < 0) {
-                       bdev_put(new);
-                       return NULL;
-               }
-               return new;
-       }
-
-       data.orig = orig;
-       data.new = new;
-       if (am_unpriv())
-               ret = userns_exec_1(c0->lxc_conf, rsync_rootfs_wrapper, &data);
-       else
-               ret = rsync_rootfs(&data);
-
-       exit(ret == 0 ? 0 : 1);
-
-err:
-       bdev_put(orig);
-       bdev_put(new);
-       return NULL;
-}
-
-static struct bdev * do_bdev_create(const char *dest, const char *type,
-                       const char *cname, struct bdev_specs *specs)
-{
-       struct bdev *bdev = bdev_get(type);
-       if (!bdev) {
-               return NULL;
-       }
-
-       if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
-                bdev_put(bdev);
-                return NULL;
-       }
-
-       return bdev;
-}
-
-/*
- * bdev_create:
- * Create a backing store for a container.
- * If successful, return a struct bdev *, with the bdev mounted and ready
- * for use.  Before completing, the caller will need to call the
- * umount operation and bdev_put().
- * @dest: the mountpoint (i.e. /var/lib/lxc/$name/rootfs)
- * @type: the bdevtype (dir, btrfs, zfs, etc)
- * @cname: the container name
- * @specs: details about the backing store to create, like fstype
- */
-struct bdev *bdev_create(const char *dest, const char *type,
-                       const char *cname, struct bdev_specs *specs)
-{
-       struct bdev *bdev;
-       char *best_options[] = {"btrfs", "zfs", "lvm", "dir", NULL};
-
-       if (!type)
-               return do_bdev_create(dest, "dir", cname, specs);
-
-       if (strcmp(type, "best") == 0) {
-               int i;
-               // try for the best backing store type, according to our
-               // opinionated preferences
-               for (i=0; best_options[i]; i++) {
-                       if ((bdev = do_bdev_create(dest, best_options[i], cname, specs)))
-                               return bdev;
-               }
-               return NULL;  // 'dir' should never fail, so this shouldn't happen
-       }
-
-       // -B lvm,dir
-       if (strchr(type, ',') != NULL) {
-               char *dup = alloca(strlen(type)+1), *saveptr = NULL, *token;
-               strcpy(dup, type);
-               for (token = strtok_r(dup, ",", &saveptr); token;
-                               token = strtok_r(NULL, ",", &saveptr)) {
-                       if ((bdev = do_bdev_create(dest, token, cname, specs)))
-                               return bdev;
-               }
-       }
-
-       return do_bdev_create(dest, type, cname, specs);
-}
-
-char *overlay_getlower(char *p)
-{
-       char *p1 = strchr(p, ':');
-       if (p1)
-               *p1 = '\0';
-       return p;
-}
-
-bool rootfs_is_blockdev(struct lxc_conf *conf)
-{
-       const struct bdev_type *q;
-       struct stat st;
-       int ret;
-
-       if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 ||
-               strlen(conf->rootfs.path) == 0)
-               return false;
-
-       ret = stat(conf->rootfs.path, &st);
-       if (ret == 0 && S_ISBLK(st.st_mode))
-               return true;
-       q = bdev_query(conf->rootfs.path);
-       if (!q)
-               return false;
-       if (strcmp(q->name, "lvm") == 0 ||
-               strcmp(q->name, "loop") == 0 ||
-               strcmp(q->name, "nbd") == 0)
-               return true;
-       return false;
-}
-
-bool bdev_destroy(struct lxc_conf *conf)
-{
-       struct bdev *r;
-       bool ret = false;
-
-       r = bdev_init(conf, conf->rootfs.path, conf->rootfs.mount, NULL);
-       if (!r)
-               return ret;
-
-       if (r->ops->destroy(r) == 0)
-               ret = true;
-       bdev_put(r);
-
-       return ret;
-}
-
-int bdev_destroy_wrapper(void *data)
-{
-       struct lxc_conf *conf = data;
-
-       if (setgid(0) < 0) {
-               ERROR("Failed to setgid to 0");
-               return -1;
-       }
-       if (setgroups(0, NULL) < 0)
-               WARN("Failed to clear groups");
-       if (setuid(0) < 0) {
-               ERROR("Failed to setuid to 0");
-               return -1;
-       }
-       if (!bdev_destroy(conf))
-               return -1;
-       else
-               return 0;
-}
-
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
new file mode 100644 (file)
index 0000000..6b29115
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * this is all just a first shot for experiment.  If we go this route, much
+ * should change.  bdev should be a directory with per-bdev file.  Things which
+ * I'm doing by calling out to userspace should sometimes be done through
+ * libraries like liblvm2
+ */
+
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <sched.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "bdev.h"
+#include "conf.h"
+#include "config.h"
+#include "error.h"
+#include "log.h"
+#include "lxc.h"
+#include "lxcaufs.h"
+#include "lxcbtrfs.h"
+#include "lxcdir.h"
+#include "lxclock.h"
+#include "lxclvm.h"
+#include "lxcloop.h"
+#include "lxcnbd.h"
+#include "lxcoverlay.h"
+#include "lxcrbd.h"
+#include "lxcrsync.h"
+#include "lxczfs.h"
+#include "namespace.h"
+#include "parse.h"
+#include "utils.h"
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+
+lxc_log_define(bdev, lxc);
+
+/* aufs */
+static const struct bdev_ops aufs_ops = {
+       .detect = &aufs_detect,
+       .mount = &aufs_mount,
+       .umount = &aufs_umount,
+       .clone_paths = &aufs_clonepaths,
+       .destroy = &aufs_destroy,
+       .create = &aufs_create,
+       .can_snapshot = true,
+       .can_backup = true,
+};
+
+/* btrfs */
+static const struct bdev_ops btrfs_ops = {
+       .detect = &btrfs_detect,
+       .mount = &btrfs_mount,
+       .umount = &btrfs_umount,
+       .clone_paths = &btrfs_clonepaths,
+       .destroy = &btrfs_destroy,
+       .create = &btrfs_create,
+       .can_snapshot = true,
+       .can_backup = true,
+};
+
+/* dir */
+static const struct bdev_ops dir_ops = {
+       .detect = &dir_detect,
+       .mount = &dir_mount,
+       .umount = &dir_umount,
+       .clone_paths = &dir_clonepaths,
+       .destroy = &dir_destroy,
+       .create = &dir_create,
+       .can_snapshot = false,
+       .can_backup = true,
+};
+
+/* loop */
+static const struct bdev_ops loop_ops = {
+       .detect = &loop_detect,
+       .mount = &loop_mount,
+       .umount = &loop_umount,
+       .clone_paths = &loop_clonepaths,
+       .destroy = &loop_destroy,
+       .create = &loop_create,
+       .can_snapshot = false,
+       .can_backup = true,
+};
+
+/* lvm */
+static const struct bdev_ops lvm_ops = {
+       .detect = &lvm_detect,
+       .mount = &lvm_mount,
+       .umount = &lvm_umount,
+       .clone_paths = &lvm_clonepaths,
+       .destroy = &lvm_destroy,
+       .create = &lvm_create,
+       .can_snapshot = true,
+       .can_backup = false,
+};
+
+/* nbd */
+const struct bdev_ops nbd_ops = {
+       .detect = &nbd_detect,
+       .mount = &nbd_mount,
+       .umount = &nbd_umount,
+       .clone_paths = &nbd_clonepaths,
+       .destroy = &nbd_destroy,
+       .create = &nbd_create,
+       .can_snapshot = true,
+       .can_backup = false,
+};
+
+/* overlay */
+static const struct bdev_ops ovl_ops = {
+       .detect = &ovl_detect,
+       .mount = &ovl_mount,
+       .umount = &ovl_umount,
+       .clone_paths = &ovl_clonepaths,
+       .destroy = &ovl_destroy,
+       .create = &ovl_create,
+       .can_snapshot = true,
+       .can_backup = true,
+};
+
+/* rbd */
+static const struct bdev_ops rbd_ops = {
+       .detect = &rbd_detect,
+       .mount = &rbd_mount,
+       .umount = &rbd_umount,
+       .clone_paths = &rbd_clonepaths,
+       .destroy = &rbd_destroy,
+       .create = &rbd_create,
+       .can_snapshot = false,
+       .can_backup = false,
+};
+
+/* zfs */
+static const struct bdev_ops zfs_ops = {
+       .detect = &zfs_detect,
+       .mount = &zfs_mount,
+       .umount = &zfs_umount,
+       .clone_paths = &zfs_clonepaths,
+       .destroy = &zfs_destroy,
+       .create = &zfs_create,
+       .can_snapshot = true,
+       .can_backup = true,
+};
+
+struct bdev_type {
+       const char *name;
+       const struct bdev_ops *ops;
+};
+
+static const struct bdev_type bdevs[] = {
+       {.name = "zfs", .ops = &zfs_ops,},
+       {.name = "lvm", .ops = &lvm_ops,},
+       {.name = "rbd", .ops = &rbd_ops,},
+       {.name = "btrfs", .ops = &btrfs_ops,},
+       {.name = "dir", .ops = &dir_ops,},
+       {.name = "aufs", .ops = &aufs_ops,},
+       {.name = "overlayfs", .ops = &ovl_ops,},
+       {.name = "loop", .ops = &loop_ops,},
+       {.name = "nbd", .ops = &nbd_ops,},
+};
+
+static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type);
+
+/* helpers */
+static const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src);
+static struct bdev *bdev_get(const char *type);
+static struct bdev *do_bdev_create(const char *dest, const char *type,
+               const char *cname, struct bdev_specs *specs);
+static int find_fstype_cb(char *buffer, void *data);
+static char *linkderef(char *path, char *dest);
+static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
+               bool maybesnap);
+
+/* the bulk of this needs to become a common helper */
+char *dir_new_path(char *src, const char *oldname, const char *name,
+               const char *oldpath, const char *lxcpath)
+{
+       char *ret, *p, *p2;
+       int l1, l2, nlen;
+
+       nlen = strlen(src) + 1;
+       l1 = strlen(oldpath);
+       p = src;
+       /* if src starts with oldpath, look for oldname only after
+        * that path */
+       if (strncmp(src, oldpath, l1) == 0) {
+               p += l1;
+               nlen += (strlen(lxcpath) - l1);
+       }
+       l2 = strlen(oldname);
+       while ((p = strstr(p, oldname)) != NULL) {
+               p += l2;
+               nlen += strlen(name) - l2;
+       }
+
+       ret = malloc(nlen);
+       if (!ret)
+               return NULL;
+
+       p = ret;
+       if (strncmp(src, oldpath, l1) == 0) {
+               p += sprintf(p, "%s", lxcpath);
+               src += l1;
+       }
+
+       while ((p2 = strstr(src, oldname)) != NULL) {
+               strncpy(p, src, p2 - src); // copy text up to oldname
+               p += p2 - src; // move target pointer (p)
+               p += sprintf(p, "%s", name); // print new name in place of oldname
+               src = p2 + l2;  // move src to end of oldname
+       }
+       sprintf(p, "%s", src);  // copy the rest of src
+       return ret;
+}
+
+/*
+ * attach_block_device returns true if all went well,
+ * meaning either a block device was attached or was not
+ * needed.  It returns false if something went wrong and
+ * container startup should be stopped.
+ */
+bool attach_block_device(struct lxc_conf *conf)
+{
+       char *path;
+
+       if (!conf->rootfs.path)
+               return true;
+       path = conf->rootfs.path;
+       if (!requires_nbd(path))
+               return true;
+       path = strchr(path, ':');
+       if (!path)
+               return false;
+       path++;
+       if (!attach_nbd(path, conf))
+               return false;
+       return true;
+}
+
+bool bdev_can_backup(struct lxc_conf *conf)
+{
+       struct bdev *bdev = bdev_init(conf, NULL, NULL, NULL);
+       bool ret;
+
+       if (!bdev)
+               return false;
+       ret = bdev->ops->can_backup;
+       bdev_put(bdev);
+       return ret;
+}
+
+/*
+ * If we're not snaphotting, then bdev_copy becomes a simple case of mount
+ * the original, mount the new, and rsync the contents.
+ */
+struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
+               const char *lxcpath, const char *bdevtype, int flags,
+               const char *bdevdata, uint64_t newsize, int *needs_rdep)
+{
+       struct bdev *orig, *new;
+       pid_t pid;
+       int ret;
+       bool snap = flags & LXC_CLONE_SNAPSHOT;
+       bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT;
+       bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE;
+       const char *src = c0->lxc_conf->rootfs.path;
+       const char *oldname = c0->name;
+       const char *oldpath = c0->config_path;
+       struct rsync_data data;
+
+       /* if the container name doesn't show up in the rootfs path, then
+        * we don't know how to come up with a new name
+        */
+       if (strstr(src, oldname) == NULL) {
+               ERROR("original rootfs path %s doesn't include container name %s",
+                       src, oldname);
+               return NULL;
+       }
+
+       orig = bdev_init(c0->lxc_conf, src, NULL, NULL);
+       if (!orig) {
+               ERROR("failed to detect blockdev type for %s", src);
+               return NULL;
+       }
+
+       if (!orig->dest) {
+               int ret;
+               size_t len;
+               struct stat sb;
+
+               len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2;
+               orig->dest = malloc(len);
+               if (!orig->dest) {
+                       ERROR("out of memory");
+                       bdev_put(orig);
+                       return NULL;
+               }
+               ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
+               if (ret < 0 || (size_t)ret >= len) {
+                       ERROR("rootfs path too long");
+                       bdev_put(orig);
+                       return NULL;
+               }
+               ret = stat(orig->dest, &sb);
+               if (ret < 0 && errno == ENOENT)
+                       if (mkdir_p(orig->dest, 0755) < 0)
+                               WARN("Error creating '%s', continuing.", orig->dest);
+       }
+
+       /*
+        * special case for snapshot - if caller requested maybe_snapshot and
+        * keepbdevtype and backing store is directory, then proceed with a copy
+        * clone rather than returning error
+        */
+       if (maybe_snap && keepbdevtype && !bdevtype && !orig->ops->can_snapshot)
+               snap = false;
+
+       /*
+        * If newtype is NULL and snapshot is set, then use overlayfs
+        */
+       if (!bdevtype && !keepbdevtype && snap && strcmp(orig->type , "dir") == 0)
+               bdevtype = "overlayfs";
+
+       if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
+               ERROR("Unsupported snapshot type for unprivileged users");
+               bdev_put(orig);
+               return NULL;
+       }
+
+       *needs_rdep = 0;
+       if (bdevtype && strcmp(orig->type, "dir") == 0 &&
+                       (strcmp(bdevtype, "aufs") == 0 ||
+                        strcmp(bdevtype, "overlayfs") == 0)) {
+               *needs_rdep = 1;
+       } else if (snap && strcmp(orig->type, "lvm") == 0 &&
+                       !lvm_is_thin_volume(orig->src)) {
+               *needs_rdep = 1;
+       }
+
+       new = bdev_get(bdevtype ? bdevtype : orig->type);
+       if (!new) {
+               ERROR("no such block device type: %s", bdevtype ? bdevtype : orig->type);
+               bdev_put(orig);
+               return NULL;
+       }
+
+       if (new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
+                               snap, newsize, c0->lxc_conf) < 0) {
+               ERROR("failed getting pathnames for cloned storage: %s", src);
+               goto err;
+       }
+
+       if (am_unpriv() && chown_mapped_root(new->src, c0->lxc_conf) < 0)
+               WARN("Failed to update ownership of %s", new->dest);
+
+       if (snap)
+               return new;
+
+       /*
+        * https://github.com/lxc/lxc/issues/131
+        * Use btrfs snapshot feature instead of rsync to restore if both orig and new are btrfs
+        */
+       if (bdevtype &&
+                       strcmp(orig->type, "btrfs") == 0 && strcmp(new->type, "btrfs") == 0 &&
+                       btrfs_same_fs(orig->dest, new->dest) == 0) {
+               if (btrfs_destroy(new) < 0) {
+                       ERROR("Error destroying %s subvolume", new->dest);
+                       goto err;
+               }
+               if (mkdir_p(new->dest, 0755) < 0) {
+                       ERROR("Error creating %s directory", new->dest);
+                       goto err;
+               }
+               if (btrfs_snapshot(orig->dest, new->dest) < 0) {
+                       ERROR("Error restoring %s to %s", orig->dest, new->dest);
+                       goto err;
+               }
+               bdev_put(orig);
+               return new;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               SYSERROR("fork");
+               goto err;
+       }
+
+       if (pid > 0) {
+               int ret = wait_for_pid(pid);
+               bdev_put(orig);
+               if (ret < 0) {
+                       bdev_put(new);
+                       return NULL;
+               }
+               return new;
+       }
+
+       data.orig = orig;
+       data.new = new;
+       if (am_unpriv())
+               ret = userns_exec_1(c0->lxc_conf, rsync_rootfs_wrapper, &data);
+       else
+               ret = rsync_rootfs(&data);
+
+       exit(ret == 0 ? 0 : 1);
+
+err:
+       bdev_put(orig);
+       bdev_put(new);
+       return NULL;
+}
+
+/*
+ * bdev_create:
+ * Create a backing store for a container.
+ * If successful, return a struct bdev *, with the bdev mounted and ready
+ * for use.  Before completing, the caller will need to call the
+ * umount operation and bdev_put().
+ * @dest: the mountpoint (i.e. /var/lib/lxc/$name/rootfs)
+ * @type: the bdevtype (dir, btrfs, zfs, rbd, etc)
+ * @cname: the container name
+ * @specs: details about the backing store to create, like fstype
+ */
+struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
+               struct bdev_specs *specs)
+{
+       struct bdev *bdev;
+       char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
+
+       if (!type)
+               return do_bdev_create(dest, "dir", cname, specs);
+
+       if (strcmp(type, "best") == 0) {
+               int i;
+               // try for the best backing store type, according to our
+               // opinionated preferences
+               for (i = 0; best_options[i]; i++) {
+                       if ((bdev = do_bdev_create(dest, best_options[i], cname, specs)))
+                               return bdev;
+               }
+               return NULL;  // 'dir' should never fail, so this shouldn't happen
+       }
+
+       // -B lvm,dir
+       if (strchr(type, ',') != NULL) {
+               char *dup = alloca(strlen(type) + 1), *saveptr = NULL, *token;
+               strcpy(dup, type);
+               for (token = strtok_r(dup, ",", &saveptr); token;
+                               token = strtok_r(NULL, ",", &saveptr)) {
+                       if ((bdev = do_bdev_create(dest, token, cname, specs)))
+                               return bdev;
+               }
+       }
+
+       return do_bdev_create(dest, type, cname, specs);
+}
+
+bool bdev_destroy(struct lxc_conf *conf)
+{
+       struct bdev *r;
+       bool ret = false;
+
+       r = bdev_init(conf, conf->rootfs.path, conf->rootfs.mount, NULL);
+       if (!r)
+               return ret;
+
+       if (r->ops->destroy(r) == 0)
+               ret = true;
+       bdev_put(r);
+
+       return ret;
+}
+
+int bdev_destroy_wrapper(void *data)
+{
+       struct lxc_conf *conf = data;
+
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+       if (!bdev_destroy(conf))
+               return -1;
+       else
+               return 0;
+}
+
+struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
+               const char *mntopts)
+{
+       struct bdev *bdev;
+       const struct bdev_type *q;
+
+       if (!src)
+               src = conf->rootfs.path;
+
+       if (!src)
+               return NULL;
+
+       q = bdev_query(conf, src);
+       if (!q)
+               return NULL;
+
+       bdev = malloc(sizeof(struct bdev));
+       if (!bdev)
+               return NULL;
+       memset(bdev, 0, sizeof(struct bdev));
+       bdev->ops = q->ops;
+       bdev->type = q->name;
+       if (mntopts)
+               bdev->mntopts = strdup(mntopts);
+       if (src)
+               bdev->src = strdup(src);
+       if (dst)
+               bdev->dest = strdup(dst);
+       if (strcmp(bdev->type, "nbd") == 0)
+               bdev->nbd_idx = conf->nbd_idx;
+
+       return bdev;
+}
+
+bool bdev_is_dir(struct lxc_conf *conf, const char *path)
+{
+       struct bdev *orig = bdev_init(conf, path, NULL, NULL);
+       bool ret = false;
+       if (!orig)
+               return ret;
+       if (strcmp(orig->type, "dir") == 0)
+               ret = true;
+       bdev_put(orig);
+       return ret;
+}
+
+void bdev_put(struct bdev *bdev)
+{
+       free(bdev->mntopts);
+       free(bdev->src);
+       free(bdev->dest);
+       free(bdev);
+}
+
+/*
+ * return block size of dev->src in units of bytes
+ */
+int blk_getsize(struct bdev *bdev, uint64_t *size)
+{
+       int fd, ret;
+       char *path = bdev->src;
+
+       if (strcmp(bdev->type, "loop") == 0)
+               path = bdev->src + 5;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes
+       close(fd);
+       return ret;
+}
+
+void detach_block_device(struct lxc_conf *conf)
+{
+       if (conf->nbd_idx != -1)
+               detach_nbd_idx(conf->nbd_idx);
+}
+
+/*
+ * Given a bdev (presumably blockdev-based), detect the fstype
+ * by trying mounting (in a private mntns) it.
+ * @bdev: bdev to investigate
+ * @type: preallocated char* in which to write the fstype
+ * @len: length of passed in char*
+ * Returns length of fstype, of -1 on error
+ */
+int detect_fs(struct bdev *bdev, char *type, int len)
+{
+       int  p[2], ret;
+       size_t linelen;
+       pid_t pid;
+       FILE *f;
+       char *sp1, *sp2, *sp3, *line = NULL;
+       char *srcdev;
+
+       if (!bdev || !bdev->src || !bdev->dest)
+               return -1;
+
+       srcdev = bdev->src;
+       if (strcmp(bdev->type, "loop") == 0)
+               srcdev = bdev->src + 5;
+
+       ret = pipe(p);
+       if (ret < 0)
+               return -1;
+       if ((pid = fork()) < 0)
+               return -1;
+       if (pid > 0) {
+               int status;
+               close(p[1]);
+               memset(type, 0, len);
+               ret = read(p[0], type, len - 1);
+               close(p[0]);
+               if (ret < 0) {
+                       SYSERROR("error reading from pipe");
+                       wait(&status);
+                       return -1;
+               } else if (ret == 0) {
+                       ERROR("child exited early - fstype not found");
+                       wait(&status);
+                       return -1;
+               }
+               wait(&status);
+               type[len - 1] = '\0';
+               INFO("detected fstype %s for %s", type, srcdev);
+               return ret;
+       }
+
+       if (unshare(CLONE_NEWNS) < 0)
+               exit(1);
+
+       if (detect_shared_rootfs()) {
+               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+                       SYSERROR("Failed to make / rslave");
+                       ERROR("Continuing...");
+               }
+       }
+
+       ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
+       if (ret < 0) {
+               ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest);
+               exit(1);
+       }
+       // if symlink, get the real dev name
+       char devpath[MAXPATHLEN];
+       char *l = linkderef(srcdev, devpath);
+       if (!l)
+               exit(1);
+       f = fopen("/proc/self/mounts", "r");
+       if (!f)
+               exit(1);
+       while (getline(&line, &linelen, f) != -1) {
+               sp1 = strchr(line, ' ');
+               if (!sp1)
+                       exit(1);
+               *sp1 = '\0';
+               if (strcmp(line, l))
+                       continue;
+               sp2 = strchr(sp1 + 1, ' ');
+               if (!sp2)
+                       exit(1);
+               *sp2 = '\0';
+               sp3 = strchr(sp2 + 1, ' ');
+               if (!sp3)
+                       exit(1);
+               *sp3 = '\0';
+               sp2++;
+               if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
+                       exit(1);
+               exit(0);
+       }
+       exit(1);
+}
+
+int do_mkfs(const char *path, const char *fstype)
+{
+       pid_t pid;
+
+       if ((pid = fork()) < 0) {
+               ERROR("error forking");
+               return -1;
+       }
+       if (pid > 0)
+               return wait_for_pid(pid);
+
+       // If the file is not a block device, we don't want mkfs to ask
+       // us about whether to proceed.
+       if (null_stdfds() < 0)
+               exit(1);
+       execlp("mkfs", "mkfs", "-t", fstype, path, (char *)NULL);
+       exit(1);
+}
+
+/*
+ * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
+ * is a block device.
+ */
+int is_blktype(struct bdev *b)
+{
+       if (strcmp(b->type, "lvm") == 0)
+               return 1;
+       return 0;
+}
+
+int mount_unknown_fs(const char *rootfs, const char *target,
+               const char *options)
+{
+       struct cbarg {
+               const char *rootfs;
+               const char *target;
+               const char *options;
+       } cbarg = {
+               .rootfs = rootfs,
+               .target = target,
+               .options = options,
+       };
+
+       /*
+        * find the filesystem type with brute force:
+        * first we check with /etc/filesystems, in case the modules
+        * are auto-loaded and fall back to the supported kernel fs
+        */
+       char *fsfile[] = {
+               "/etc/filesystems",
+               "/proc/filesystems",
+       };
+
+       size_t i;
+       for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) {
+
+               int ret;
+
+               if (access(fsfile[i], F_OK))
+                       continue;
+
+               ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
+               if (ret < 0) {
+                       ERROR("failed to parse '%s'", fsfile[i]);
+                       return -1;
+               }
+
+               if (ret)
+                       return 0;
+       }
+
+       ERROR("failed to determine fs type for '%s'", rootfs);
+       return -1;
+}
+
+bool rootfs_is_blockdev(struct lxc_conf *conf)
+{
+       const struct bdev_type *q;
+       struct stat st;
+       int ret;
+
+       if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 ||
+               strlen(conf->rootfs.path) == 0)
+               return false;
+
+       ret = stat(conf->rootfs.path, &st);
+       if (ret == 0 && S_ISBLK(st.st_mode))
+               return true;
+       q = bdev_query(conf, conf->rootfs.path);
+       if (!q)
+               return false;
+       if (strcmp(q->name, "lvm") == 0 ||
+               strcmp(q->name, "loop") == 0 ||
+               strcmp(q->name, "nbd") == 0)
+               return true;
+       return false;
+}
+
+static struct bdev *do_bdev_create(const char *dest, const char *type,
+               const char *cname, struct bdev_specs *specs)
+{
+
+       struct bdev *bdev = bdev_get(type);
+       if (!bdev) {
+               return NULL;
+       }
+
+       if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
+                bdev_put(bdev);
+                return NULL;
+       }
+
+       return bdev;
+}
+
+static struct bdev *bdev_get(const char *type)
+{
+       int i;
+       struct bdev *bdev;
+
+       for (i = 0; i < numbdevs; i++) {
+               if (strcmp(bdevs[i].name, type) == 0)
+                       break;
+       }
+       if (i == numbdevs)
+               return NULL;
+       bdev = malloc(sizeof(struct bdev));
+       if (!bdev)
+               return NULL;
+       memset(bdev, 0, sizeof(struct bdev));
+       bdev->ops = bdevs[i].ops;
+       bdev->type = bdevs[i].name;
+       return bdev;
+}
+
+static const struct bdev_type *get_bdev_by_name(const char *name)
+{
+       int i;
+
+       for (i = 0; i < numbdevs; i++) {
+               if (strcmp(bdevs[i].name, name) == 0)
+                       return &bdevs[i];
+       }
+
+       ERROR("Backing store %s unknown but not caught earlier\n", name);
+       return NULL;
+}
+
+static const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src)
+{
+       int i;
+
+       if (conf->rootfs.bdev_type)
+               return get_bdev_by_name(conf->rootfs.bdev_type);
+
+       for (i = 0; i < numbdevs; i++) {
+               int r;
+               r = bdevs[i].ops->detect(src);
+               if (r)
+                       break;
+       }
+
+       if (i == numbdevs)
+               return NULL;
+       return &bdevs[i];
+}
+
+/*
+ * These are copied from conf.c.  However as conf.c will be moved to using
+ * the callback system, they can be pulled from there eventually, so we
+ * don't need to pollute utils.c with these low level functions
+ */
+static int find_fstype_cb(char* buffer, void *data)
+{
+       struct cbarg {
+               const char *rootfs;
+               const char *target;
+               const char *options;
+       } *cbarg = data;
+
+       unsigned long mntflags;
+       char *mntdata;
+       char *fstype;
+
+       /* we don't try 'nodev' entries */
+       if (strstr(buffer, "nodev"))
+               return 0;
+
+       fstype = buffer;
+       fstype += lxc_char_left_gc(fstype, strlen(fstype));
+       fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
+
+       DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
+             cbarg->rootfs, cbarg->target, fstype);
+
+       if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return 0;
+       }
+
+       if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
+               DEBUG("mount failed with error: %s", strerror(errno));
+               free(mntdata);
+               return 0;
+       }
+
+       free(mntdata);
+
+       INFO("mounted '%s' on '%s', with fstype '%s'",
+            cbarg->rootfs, cbarg->target, fstype);
+
+       return 1;
+}
+
+static char *linkderef(char *path, char *dest)
+{
+       struct stat sbuf;
+       ssize_t ret;
+
+       ret = stat(path, &sbuf);
+       if (ret < 0)
+               return NULL;
+       if (!S_ISLNK(sbuf.st_mode))
+               return path;
+       ret = readlink(path, dest, MAXPATHLEN);
+       if (ret < 0) {
+               SYSERROR("error reading link %s", path);
+               return NULL;
+       } else if (ret >= MAXPATHLEN) {
+               ERROR("link in %s too long", path);
+               return NULL;
+       }
+       dest[ret] = '\0';
+       return dest;
+}
+
+/*
+ * is an unprivileged user allowed to make this kind of snapshot
+ */
+static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
+               bool maybesnap)
+{
+       if (!t) {
+               // new type will be same as original
+               // (unless snap && b->type == dir, in which case it will be
+               // overlayfs -- which is also allowed)
+               if (strcmp(b->type, "dir") == 0 ||
+                               strcmp(b->type, "aufs") == 0 ||
+                               strcmp(b->type, "overlayfs") == 0 ||
+                               strcmp(b->type, "btrfs") == 0 ||
+                               strcmp(b->type, "loop") == 0)
+                       return true;
+               return false;
+       }
+
+       // unprivileged users can copy and snapshot dir, overlayfs,
+       // and loop.  In particular, not zfs, btrfs, or lvm.
+       if (strcmp(t, "dir") == 0 ||
+               strcmp(t, "aufs") == 0 ||
+               strcmp(t, "overlayfs") == 0 ||
+               strcmp(t, "btrfs") == 0 ||
+               strcmp(t, "loop") == 0)
+               return true;
+       return false;
+}
+
+bool is_valid_bdev_type(const char *type)
+{
+       if (strcmp(type, "dir") == 0 ||
+                       strcmp(type, "btrfs") == 0 ||
+                       strcmp(type, "aufs") == 0 ||
+                       strcmp(type, "loop") == 0 ||
+                       strcmp(type, "lvm") == 0 ||
+                       strcmp(type, "nbd") == 0 ||
+                       strcmp(type, "overlayfs") == 0 ||
+                       strcmp(type, "rbd") == 0 ||
+                       strcmp(type, "zfs") == 0)
+               return true;
+       return false;
+}
similarity index 87%
rename from src/lxc/bdev.h
rename to src/lxc/bdev/bdev.h
index f7b3fca..3f21e84 100644 (file)
  * aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, nbd (qcow2, raw, vdi, qed)
  */
 
-#include "config.h"
-#include <stdint.h>
 #include <lxc/lxccontainer.h>
+#include <stdint.h>
 #include <sys/mount.h>
 
+#include "config.h"
 
 /* define constants if the kernel/glibc headers don't define them */
 #ifndef MS_DIRSYNC
@@ -58,6 +58,9 @@
 #define MS_STRICTATIME (1 << 24)
 #endif
 
+#define DEFAULT_FS_SIZE 1073741824
+#define DEFAULT_FSTYPE "ext3"
+
 struct bdev;
 
 struct bdev_ops {
@@ -97,8 +100,6 @@ struct bdev {
        int nbd_idx;
 };
 
-char *overlay_getlower(char *p);
-
 bool bdev_is_dir(struct lxc_conf *conf, const char *path);
 bool bdev_can_backup(struct lxc_conf *conf);
 
@@ -127,6 +128,17 @@ bool bdev_destroy(struct lxc_conf *conf);
 /* callback function to be used with userns_exec_1() */
 int bdev_destroy_wrapper(void *data);
 
+/* Some helpers for lvm, rdb, and/or loop:
+ * Maybe they should move to a separate implementation and header-file
+ * (bdev_utils.{c,h}) which can be included in bdev.c?
+ */
+int blk_getsize(struct bdev *bdev, uint64_t *size);
+int detect_fs(struct bdev *bdev, char *type, int len);
+int do_mkfs(const char *path, const char *fstype);
+int is_blktype(struct bdev *b);
+int mount_unknown_fs(const char *rootfs, const char *target,
+               const char *options);
+bool rootfs_is_blockdev(struct lxc_conf *conf);
 /*
  * these are really for qemu-nbd support, as container shutdown
  * must explicitly request device detach.
@@ -134,5 +146,6 @@ int bdev_destroy_wrapper(void *data);
 bool attach_block_device(struct lxc_conf *conf);
 void detach_block_device(struct lxc_conf *conf);
 
-bool rootfs_is_blockdev(struct lxc_conf *conf);
-#endif
+bool is_valid_bdev_type(const char *type);
+
+#endif // __LXC_BDEV_H
diff --git a/src/lxc/bdev/lxcaufs.c b/src/lxc/bdev/lxcaufs.c
new file mode 100644 (file)
index 0000000..0152966
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcaufs.h"
+#include "lxcrsync.h"
+#include "utils.h"
+
+lxc_log_define(lxcaufs, lxc);
+
+/* the bulk of this needs to become a common helper */
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+               const char *oldpath, const char *lxcpath);
+
+int aufs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       if (!snap) {
+               ERROR("aufs is only for snapshot clones");
+               return -22;
+       }
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
+       if (!new->dest)
+               return -1;
+       if (mkdir_p(new->dest, 0755) < 0)
+               return -1;
+
+       if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
+               WARN("Failed to update ownership of %s", new->dest);
+
+       if (strcmp(orig->type, "dir") == 0) {
+               char *delta, *lastslash;
+               int ret, len, lastslashidx;
+
+               // if we have /var/lib/lxc/c2/rootfs, then delta will be
+               //            /var/lib/lxc/c2/delta0
+               lastslash = strrchr(new->dest, '/');
+               if (!lastslash)
+                       return -22;
+               if (strlen(lastslash) < 7)
+                       return -22;
+               lastslash++;
+               lastslashidx = lastslash - new->dest;
+
+               delta = malloc(lastslashidx + 7);
+               if (!delta)
+                       return -1;
+               strncpy(delta, new->dest, lastslashidx+1);
+               strcpy(delta+lastslashidx, "delta0");
+               if ((ret = mkdir(delta, 0755)) < 0) {
+                       SYSERROR("error: mkdir %s", delta);
+                       free(delta);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
+                       WARN("Failed to update ownership of %s", delta);
+
+               // the src will be 'aufs:lowerdir:upperdir'
+               len = strlen(delta) + strlen(orig->src) + 12;
+               new->src = malloc(len);
+               if (!new->src) {
+                       free(delta);
+                       return -ENOMEM;
+               }
+               ret = snprintf(new->src, len, "aufs:%s:%s", orig->src, delta);
+               free(delta);
+               if (ret < 0 || ret >= len)
+                       return -ENOMEM;
+       } else if (strcmp(orig->type, "aufs") == 0) {
+               // What exactly do we want to do here?
+               // I think we want to use the original lowerdir, with a
+               // private delta which is originally rsynced from the
+               // original delta
+               char *osrc, *odelta, *nsrc, *ndelta;
+               int len, ret;
+               if (!(osrc = strdup(orig->src)))
+                       return -22;
+               nsrc = strchr(osrc, ':') + 1;
+               if (nsrc != osrc + 5 || (odelta = strchr(nsrc, ':')) == NULL) {
+                       free(osrc);
+                       return -22;
+               }
+               *odelta = '\0';
+               odelta++;
+               ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
+               if (!ndelta) {
+                       free(osrc);
+                       return -ENOMEM;
+               }
+               if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
+                       SYSERROR("error: mkdir %s", ndelta);
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
+                       WARN("Failed to update ownership of %s", ndelta);
+
+               struct rsync_data_char rdata;
+               rdata.src = odelta;
+               rdata.dest = ndelta;
+               if (am_unpriv())
+                       ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata);
+               else
+                       ret = rsync_delta(&rdata);
+               if (ret) {
+                       free(osrc);
+                       free(ndelta);
+                       ERROR("copying aufs delta");
+                       return -1;
+               }
+               len = strlen(nsrc) + strlen(ndelta) + 12;
+               new->src = malloc(len);
+               if (!new->src) {
+                       free(osrc);
+                       free(ndelta);
+                       return -ENOMEM;
+               }
+               ret = snprintf(new->src, len, "aufs:%s:%s", nsrc, ndelta);
+               free(osrc);
+               free(ndelta);
+               if (ret < 0 || ret >= len)
+                       return -ENOMEM;
+       } else {
+               ERROR("aufs clone of %s container is not yet supported",
+                       orig->type);
+               // Note, supporting this will require aufs_mount supporting
+               // mounting of the underlay.  No big deal, just needs to be done.
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * to say 'lxc-create -t ubuntu -n o1 -B aufs' means you want
+ * $lxcpath/$lxcname/rootfs to have the created container, while all
+ * changes after starting the container are written to
+ * $lxcpath/$lxcname/delta0
+ */
+int aufs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       char *delta;
+       int ret, len = strlen(dest), newlen;
+
+       if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
+               return -1;
+
+       if (!(bdev->dest = strdup(dest))) {
+               ERROR("Out of memory");
+               return -1;
+       }
+
+       delta = alloca(strlen(dest)+1);
+       strcpy(delta, dest);
+       strcpy(delta+len-6, "delta0");
+
+       if (mkdir_p(delta, 0755) < 0) {
+               ERROR("Error creating %s", delta);
+               return -1;
+       }
+
+       /* aufs:lower:upper */
+       newlen = (2 * len) + strlen("aufs:") + 2;
+       bdev->src = malloc(newlen);
+       if (!bdev->src) {
+               ERROR("Out of memory");
+               return -1;
+       }
+       ret = snprintf(bdev->src, newlen, "aufs:%s:%s", dest, delta);
+       if (ret < 0 || ret >= newlen)
+               return -1;
+
+       if (mkdir_p(bdev->dest, 0755) < 0) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int aufs_destroy(struct bdev *orig)
+{
+       char *upper;
+
+       if (strncmp(orig->src, "aufs:", 5) != 0)
+               return -22;
+       upper = strchr(orig->src + 5, ':');
+       if (!upper)
+               return -22;
+       upper++;
+       return lxc_rmdir_onedev(upper, NULL);
+}
+
+int aufs_detect(const char *path)
+{
+       if (strncmp(path, "aufs:", 5) == 0)
+               return 1; // take their word for it
+       return 0;
+}
+
+int aufs_mount(struct bdev *bdev)
+{
+       char *tmp, *options, *dup, *lower, *upper;
+       int len;
+       unsigned long mntflags;
+       char *mntdata;
+       int ret;
+       const char *xinopath = "/dev/shm/aufs.xino";
+
+       if (strcmp(bdev->type, "aufs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       //  separately mount it first
+       //  mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest
+       dup = alloca(strlen(bdev->src)+1);
+       strcpy(dup, bdev->src);
+       /* support multiple lower layers */
+       if (!(lower = strstr(dup, ":/")))
+                       return -22;
+       lower++;
+       upper = lower;
+       while ((tmp = strstr(++upper, ":/"))) {
+               upper = tmp;
+       }
+       if (--upper == lower)
+               return -22;
+       *upper = '\0';
+       upper++;
+
+       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return -22;
+       }
+
+       // TODO We should check whether bdev->src is a blockdev, and if so
+       // but for now, only support aufs of a basic directory
+
+       // AUFS does not work on top of certain filesystems like (XFS or Btrfs)
+       // so add xino=/dev/shm/aufs.xino parameter to mount options.
+       // The same xino option can be specified to multiple aufs mounts, and
+       // a xino file is not shared among multiple aufs mounts.
+       //
+       // see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
+       //     http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
+       if (mntdata) {
+               len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
+               options = alloca(len);
+               ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
+       }
+       else {
+               len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
+               options = alloca(len);
+               ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
+       }
+
+       if (ret < 0 || ret >= len) {
+               free(mntdata);
+               return -1;
+       }
+
+       ret = mount(lower, bdev->dest, "aufs", MS_MGC_VAL | mntflags, options);
+       if (ret < 0)
+               SYSERROR("aufs: error mounting %s onto %s options %s",
+                       lower, bdev->dest, options);
+       else
+               INFO("aufs: mounted %s onto %s options %s",
+                       lower, bdev->dest, options);
+       return ret;
+}
+
+int aufs_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "aufs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
+
+char *aufs_get_rootfs(const char *rootfs_path, size_t *rootfslen)
+{
+       char *rootfsdir = NULL;
+       char *s1 = NULL;
+       char *s2 = NULL;
+       char *s3 = NULL;
+
+       if (!rootfs_path || !rootfslen)
+               return NULL;
+
+       s1 = strdup(rootfs_path);
+       if (!s1)
+               return NULL;
+
+       if ((s2 = strstr(s1, ":/"))) {
+               s2 = s2 + 1;
+               if ((s3 = strstr(s2, ":/")))
+                       *s3 = '\0';
+               rootfsdir = strdup(s2);
+               if (!rootfsdir) {
+                       free(s1);
+                       return NULL;
+               }
+       }
+
+       if (!rootfsdir)
+               rootfsdir = s1;
+       else
+               free(s1);
+
+       *rootfslen = strlen(rootfsdir);
+
+       return rootfsdir;
+}
+
+int aufs_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
+               const char *lxc_name, const char *lxc_path)
+{
+       char lxcpath[MAXPATHLEN];
+       char *rootfs_path = NULL;
+       char *rootfsdir = NULL;
+       char *scratch = NULL;
+       char *tmp = NULL;
+       char *upperdir = NULL;
+       char **opts = NULL;
+       int fret = -1;
+       int ret = 0;
+       size_t arrlen = 0;
+       size_t i;
+       size_t len = 0;
+       size_t rootfslen = 0;
+
+       /* When rootfs == NULL we have a container without a rootfs. */
+       if (rootfs && rootfs->path)
+               rootfs_path = rootfs->path;
+
+       opts = lxc_string_split(mntent->mnt_opts, ',');
+       if (opts)
+               arrlen = lxc_array_len((void **)opts);
+       else
+               goto err;
+
+       for (i = 0; i < arrlen; i++) {
+               if (strstr(opts[i], "br=") && (strlen(opts[i]) > (len = strlen("br="))))
+                       tmp = opts[i] + len;
+       }
+       if (!tmp)
+               goto err;
+
+       upperdir = strtok_r(tmp, ":=", &scratch);
+       if (!upperdir)
+               goto err;
+
+       if (rootfs_path) {
+               ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       goto err;
+
+               rootfsdir = aufs_get_rootfs(rootfs->path, &rootfslen);
+               if (!rootfsdir)
+                       goto err;
+       }
+
+       /*
+        * We neither allow users to create upperdirs and workdirs outside the
+        * containerdir nor inside the rootfs. The latter might be debatable.
+        * When we have a container without a rootfs we skip the checks.
+        */
+       ret = 0;
+       if (!rootfs_path)
+               ret = mkdir_p(upperdir, 0755);
+       else if ((strncmp(upperdir, lxcpath, strlen(lxcpath)) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
+               ret = mkdir_p(upperdir, 0755);
+       if (ret < 0)
+               WARN("Failed to create upperdir");
+
+       fret = 0;
+
+err:
+       free(rootfsdir);
+       lxc_free_array((void **)opts, free);
+       return fret;
+}
+
diff --git a/src/lxc/bdev/lxcaufs.h b/src/lxc/bdev/lxcaufs.h
new file mode 100644 (file)
index 0000000..fa623f7
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_AUFS_H
+#define __LXC_AUFS_H
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+#if IS_BIONIC
+#include <../include/lxcmntent.h>
+#else
+#include <mntent.h>
+#endif
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/* defined in conf.h */
+struct lxc_rootfs;
+
+/*
+ * Functions associated with an aufs bdev struct.
+ */
+int aufs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int aufs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int aufs_destroy(struct bdev *orig);
+int aufs_detect(const char *path);
+int aufs_mount(struct bdev *bdev);
+int aufs_umount(struct bdev *bdev);
+
+/*
+ * Get rootfs path for aufs backed containers. Allocated memory must be freed
+ * by caller.
+ */
+char *aufs_get_rootfs(const char *rootfs_path, size_t *rootfslen);
+
+/*
+ * Create directories for aufs mounts.
+ */
+int aufs_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
+               const char *lxc_name, const char *lxc_path);
+
+#endif /* __LXC_AUFS_H */
diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c
new file mode 100644 (file)
index 0000000..5ee6dd3
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcbtrfs.h"
+#include "lxcrsync.h"
+#include "utils.h"
+
+lxc_log_define(lxcbtrfs, lxc);
+
+/* defined in lxccontainer.c: needs to become common helper */
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+                         const char *oldpath, const char *lxcpath);
+
+/*
+ * Return the full path of objid under dirid.  Let's say dirid is
+ * /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c.  Then we will
+ * return a/b/c.  If instead objid is for /lxc/c1/rootfs/a, we will
+ * simply return a.
+ */
+char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name,
+                           int name_len)
+{
+       struct btrfs_ioctl_ino_lookup_args args;
+       int ret, e;
+       size_t len;
+       char *retpath;
+
+       memset(&args, 0, sizeof(args));
+       args.treeid = dir_id;
+       args.objectid = objid;
+
+       ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+       e = errno;
+       if (ret) {
+               ERROR("%s: ERROR: Failed to lookup path for %llu %llu %s - %s\n",
+                                __func__, (unsigned long long) dir_id,
+                                (unsigned long long) objid,
+                                name, strerror(e));
+               return NULL;
+       } else
+               INFO("%s: got path for %llu %llu - %s\n", __func__,
+                       (unsigned long long) objid, (unsigned long long) dir_id,
+                       name);
+
+       if (args.name[0]) {
+               /*
+                * we're in a subdirectory of ref_tree, the kernel ioctl
+                * puts a / in there for us
+                */
+               len = strlen(args.name) + name_len + 2;
+               retpath = malloc(len);
+               if (!retpath)
+                       return NULL;
+               strcpy(retpath, args.name);
+               strcat(retpath, "/");
+               strncat(retpath, name, name_len);
+       } else {
+               /* we're at the root of ref_tree */
+               len = name_len + 1;
+               retpath = malloc(len);
+               if (!retpath)
+                       return NULL;
+               *retpath = '\0';
+               strncat(retpath, name, name_len);
+       }
+       return retpath;
+}
+
+//
+// btrfs ops
+//
+
+int btrfs_list_get_path_rootid(int fd, u64 *treeid)
+{
+       int  ret;
+       struct btrfs_ioctl_ino_lookup_args args;
+
+       memset(&args, 0, sizeof(args));
+       args.objectid = BTRFS_FIRST_FREE_OBJECTID;
+
+       ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+       if (ret < 0) {
+               WARN("Warning: can't perform the search -%s\n",
+                               strerror(errno));
+               return ret;
+       }
+       *treeid = args.treeid;
+       return 0;
+}
+
+bool is_btrfs_fs(const char *path)
+{
+       int fd, ret;
+       struct btrfs_ioctl_space_args sargs;
+
+       // make sure this is a btrfs filesystem
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return false;
+       sargs.space_slots = 0;
+       sargs.total_spaces = 0;
+       ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &sargs);
+       close(fd);
+       if (ret < 0)
+               return false;
+
+       return true;
+}
+
+int btrfs_detect(const char *path)
+{
+       struct stat st;
+       int ret;
+
+       if (!is_btrfs_fs(path))
+               return 0;
+
+       // and make sure it's a subvolume.
+       ret = stat(path, &st);
+       if (ret < 0)
+               return 0;
+
+       if (st.st_ino == 256 && S_ISDIR(st.st_mode))
+               return 1;
+
+       return 0;
+}
+
+int btrfs_mount(struct bdev *bdev)
+{
+       unsigned long mntflags;
+       char *mntdata;
+       int ret;
+
+       if (strcmp(bdev->type, "btrfs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return -22;
+       }
+
+       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+       free(mntdata);
+       return ret;
+}
+
+int btrfs_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "btrfs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
+
+static int btrfs_subvolume_create(const char *path)
+{
+       int ret, fd = -1;
+       struct btrfs_ioctl_vol_args  args;
+       char *p, *newfull = strdup(path);
+
+       if (!newfull) {
+               ERROR("Error: out of memory");
+               return -1;
+       }
+
+       p = strrchr(newfull, '/');
+       if (!p) {
+               ERROR("bad path: %s", path);
+               free(newfull);
+               return -1;
+       }
+       *p = '\0';
+
+       fd = open(newfull, O_RDONLY);
+       if (fd < 0) {
+               ERROR("Error opening %s", newfull);
+               free(newfull);
+               return -1;
+       }
+
+       memset(&args, 0, sizeof(args));
+       strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
+       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
+       ret = ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args);
+       INFO("btrfs: snapshot create ioctl returned %d", ret);
+
+       free(newfull);
+       close(fd);
+       return ret;
+}
+
+int btrfs_same_fs(const char *orig, const char *new)
+{
+       int fd_orig = -1, fd_new = -1, ret = -1;
+       struct btrfs_ioctl_fs_info_args orig_args, new_args;
+
+       fd_orig = open(orig, O_RDONLY);
+       if (fd_orig < 0) {
+               SYSERROR("Error opening original rootfs %s", orig);
+               goto out;
+       }
+       ret = ioctl(fd_orig, BTRFS_IOC_FS_INFO, &orig_args);
+       if (ret < 0) {
+               SYSERROR("BTRFS_IOC_FS_INFO %s", orig);
+               goto out;
+       }
+
+       fd_new = open(new, O_RDONLY);
+       if (fd_new < 0) {
+               SYSERROR("Error opening new container dir %s", new);
+               ret = -1;
+               goto out;
+       }
+       ret = ioctl(fd_new, BTRFS_IOC_FS_INFO, &new_args);
+       if (ret < 0) {
+               SYSERROR("BTRFS_IOC_FS_INFO %s", new);
+               goto out;
+       }
+
+       if (strncmp(orig_args.fsid, new_args.fsid, BTRFS_FSID_SIZE) != 0) {
+               ret = -1;
+               goto out;
+       }
+       ret = 0;
+out:
+       if (fd_new != -1)
+               close(fd_new);
+       if (fd_orig != -1)
+               close(fd_orig);
+       return ret;
+}
+
+int btrfs_snapshot(const char *orig, const char *new)
+{
+       int fd = -1, fddst = -1, ret = -1;
+       struct btrfs_ioctl_vol_args_v2  args;
+       char *newdir, *newname, *newfull = NULL;
+
+       newfull = strdup(new);
+       if (!newfull) {
+               ERROR("Error: out of memory");
+               goto out;
+       }
+       // make sure the directory doesn't already exist
+       if (rmdir(newfull) < 0 && errno != ENOENT) {
+               SYSERROR("Error removing empty new rootfs");
+               goto out;
+       }
+       newname = basename(newfull);
+       newdir = dirname(newfull);
+       fd = open(orig, O_RDONLY);
+       if (fd < 0) {
+               SYSERROR("Error opening original rootfs %s", orig);
+               goto out;
+       }
+       fddst = open(newdir, O_RDONLY);
+       if (fddst < 0) {
+               SYSERROR("Error opening new container dir %s", newdir);
+               goto out;
+       }
+
+       memset(&args, 0, sizeof(args));
+       args.fd = fd;
+       strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
+       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
+       ret = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
+       INFO("btrfs: snapshot create ioctl returned %d", ret);
+
+out:
+       if (fddst != -1)
+               close(fddst);
+       if (fd != -1)
+               close(fd);
+       free(newfull);
+       return ret;
+}
+
+static int btrfs_snapshot_wrapper(void *data)
+{
+       struct rsync_data_char *arg = data;
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+       return btrfs_snapshot(arg->src, arg->dest);
+}
+
+int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+                    const char *cname, const char *oldpath,
+                    const char *lxcpath, int snap, uint64_t newsize,
+                    struct lxc_conf *conf)
+{
+       if (!orig->dest || !orig->src)
+               return -1;
+
+       if (strcmp(orig->type, "btrfs")) {
+               int len, ret;
+               if (snap) {
+                       ERROR("btrfs snapshot from %s backing store is not supported",
+                               orig->type);
+                       return -1;
+               }
+               len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+               new->src = malloc(len);
+               if (!new->src)
+                       return -1;
+               ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
+               if (ret < 0 || ret >= len)
+                       return -1;
+       } else {
+               // in case rootfs is in custom path, reuse it
+               if ((new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath)) == NULL)
+                       return -1;
+
+       }
+
+       if ((new->dest = strdup(new->src)) == NULL)
+               return -1;
+
+       if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
+               return -1;
+
+       if (snap) {
+               struct rsync_data_char sdata;
+               if (!am_unpriv())
+                       return btrfs_snapshot(orig->dest, new->dest);
+               sdata.dest = new->dest;
+               sdata.src = orig->dest;
+               return userns_exec_1(conf, btrfs_snapshot_wrapper, &sdata);
+       }
+
+       if (rmdir(new->dest) < 0 && errno != ENOENT) {
+               SYSERROR("removing %s", new->dest);
+               return -1;
+       }
+
+       return btrfs_subvolume_create(new->dest);
+}
+
+static int btrfs_do_destroy_subvol(const char *path)
+{
+       int ret, fd = -1;
+       struct btrfs_ioctl_vol_args  args;
+       char *p, *newfull = strdup(path);
+
+       if (!newfull) {
+               ERROR("Error: out of memory");
+               return -1;
+       }
+
+       p = strrchr(newfull, '/');
+       if (!p) {
+               ERROR("bad path: %s", path);
+               free(newfull);
+               return -1;
+       }
+       *p = '\0';
+
+       fd = open(newfull, O_RDONLY);
+       if (fd < 0) {
+               SYSERROR("Error opening %s", newfull);
+               free(newfull);
+               return -1;
+       }
+
+       memset(&args, 0, sizeof(args));
+       strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
+       args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
+       ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
+       INFO("btrfs: snapshot destroy ioctl returned %d for %s", ret, path);
+       if (ret < 0 && errno == EPERM)
+               ERROR("Is the rootfs mounted with -o user_subvol_rm_allowed?");
+
+       free(newfull);
+       close(fd);
+       return ret;
+}
+
+static int get_btrfs_tree_idx(struct my_btrfs_tree *tree, u64 id)
+{
+       int i;
+       if (!tree)
+               return -1;
+       for (i = 0; i < tree->num; i++) {
+               if (tree->nodes[i].objid == id)
+                       return i;
+       }
+       return -1;
+}
+
+static struct my_btrfs_tree *create_my_btrfs_tree(u64 id, const char *path,
+                                                 int name_len)
+{
+       struct my_btrfs_tree *tree;
+
+       tree = malloc(sizeof(struct my_btrfs_tree));
+       if (!tree)
+               return NULL;
+       tree->nodes = malloc(sizeof(struct mytree_node));
+       if (!tree->nodes) {
+               free(tree);
+               return NULL;
+       }
+       tree->num = 1;
+       tree->nodes[0].dirname = NULL;
+       tree->nodes[0].name = strdup(path);
+       if (!tree->nodes[0].name) {
+               free(tree->nodes);
+               free(tree);
+               return NULL;
+       }
+       tree->nodes[0].parentid = 0;
+       tree->nodes[0].objid = id;
+       return tree;
+}
+
+static bool update_tree_node(struct mytree_node *n, u64 id, u64 parent,
+                            char *name, int name_len, char *dirname)
+{
+       if (id)
+               n->objid = id;
+       if (parent)
+               n->parentid = parent;
+       if (name) {
+               n->name = malloc(name_len + 1);
+               if (!n->name)
+                       return false;
+               strncpy(n->name, name, name_len);
+               n->name[name_len] = '\0';
+       }
+       if (dirname) {
+               n->dirname = malloc(strlen(dirname) + 1);
+               if (!n->dirname) {
+                       free(n->name);
+                       return false;
+               }
+               strcpy(n->dirname, dirname);
+       }
+       return true;
+}
+
+static bool add_btrfs_tree_node(struct my_btrfs_tree *tree, u64 id, u64 parent,
+                               char *name, int name_len, char *dirname)
+{
+       struct mytree_node *tmp;
+
+       int i = get_btrfs_tree_idx(tree, id);
+       if (i != -1)
+               return update_tree_node(&tree->nodes[i], id, parent, name,
+                               name_len, dirname);
+
+       tmp = realloc(tree->nodes, (tree->num+1) * sizeof(struct mytree_node));
+       if (!tmp)
+               return false;
+       tree->nodes = tmp;
+       memset(&tree->nodes[tree->num], 0, sizeof(struct mytree_node));
+       if (!update_tree_node(&tree->nodes[tree->num], id, parent, name,
+                               name_len, dirname))
+               return false;
+       tree->num++;
+       return true;
+}
+
+static void free_btrfs_tree(struct my_btrfs_tree *tree)
+{
+       int i;
+       if (!tree)
+               return;
+       for (i = 0; i < tree->num;  i++) {
+               free(tree->nodes[i].name);
+               free(tree->nodes[i].dirname);
+       }
+       free(tree->nodes);
+       free(tree);
+}
+
+/*
+ * Given a @tree of subvolumes under @path, ask btrfs to remove each
+ * subvolume
+ */
+static bool do_remove_btrfs_children(struct my_btrfs_tree *tree, u64 root_id,
+                                    const char *path)
+{
+       int i;
+       char *newpath;
+       size_t len;
+
+       for (i = 0; i < tree->num; i++) {
+               if (tree->nodes[i].parentid == root_id) {
+                       if (!tree->nodes[i].dirname) {
+                               WARN("Odd condition: child objid with no name under %s\n", path);
+                               continue;
+                       }
+                       len = strlen(path) + strlen(tree->nodes[i].dirname) + 2;
+                       newpath = malloc(len);
+                       if (!newpath) {
+                               ERROR("Out of memory");
+                               return false;
+                       }
+                       snprintf(newpath, len, "%s/%s", path, tree->nodes[i].dirname);
+                       if (!do_remove_btrfs_children(tree, tree->nodes[i].objid, newpath)) {
+                               ERROR("Failed to prune %s\n", tree->nodes[i].name);
+                               free(newpath);
+                               return false;
+                       }
+                       if (btrfs_do_destroy_subvol(newpath) != 0) {
+                               ERROR("Failed to remove %s\n", newpath);
+                               free(newpath);
+                               return false;
+                       }
+                       free(newpath);
+               }
+       }
+       return true;
+}
+
+static int btrfs_recursive_destroy(const char *path)
+{
+       u64 root_id;
+       int fd;
+       struct btrfs_ioctl_search_args args;
+       struct btrfs_ioctl_search_key *sk = &args.key;
+       struct btrfs_ioctl_search_header sh;
+       struct btrfs_root_ref *ref;
+       struct my_btrfs_tree *tree;
+       int ret, e, i;
+       unsigned long off = 0;
+       int name_len;
+       char *name;
+       char *tmppath;
+       u64 dir_id;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               ERROR("Failed to open %s\n", path);
+               return -1;
+       }
+
+       if (btrfs_list_get_path_rootid(fd, &root_id)) {
+               e = errno;
+               close(fd);
+               if (e == EPERM || e == EACCES) {
+                       WARN("Will simply try removing");
+                       goto ignore_search;
+               }
+
+               return -1;
+       }
+
+       tree = create_my_btrfs_tree(root_id, path, strlen(path));
+       if (!tree) {
+               ERROR("Out of memory\n");
+               close(fd);
+               return -1;
+       }
+       /* Walk all subvols looking for any under this id */
+       memset(&args, 0, sizeof(args));
+
+       /* search in the tree of tree roots */
+       sk->tree_id = 1;
+
+       sk->max_type = BTRFS_ROOT_REF_KEY;
+       sk->min_type = BTRFS_ROOT_ITEM_KEY;
+       sk->min_objectid = 0;
+       sk->max_objectid = (u64)-1;
+       sk->max_offset = (u64)-1;
+       sk->min_offset = 0;
+       sk->max_transid = (u64)-1;
+       sk->nr_items = 4096;
+
+       while(1) {
+               ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+               e = errno;
+               if (ret < 0) {
+                       close(fd);
+                       free_btrfs_tree(tree);
+                       if (e == EPERM || e == EACCES) {
+                               WARN("Warn: can't perform the search under %s. Will simply try removing", path);
+                               goto ignore_search;
+                       }
+
+                       ERROR("Error: can't perform the search under %s\n", path);
+                       return -1;
+               }
+               if (sk->nr_items == 0)
+                       break;
+
+               off = 0;
+               for (i = 0; i < sk->nr_items; i++) {
+                       memcpy(&sh, args.buf + off, sizeof(sh));
+                       off += sizeof(sh);
+                       /*
+                        * A backref key with the name and dirid of the parent
+                        * comes followed by the reoot ref key which has the
+                        * name of the child subvol in question.
+                        */
+                       if (sh.objectid != root_id && sh.type == BTRFS_ROOT_BACKREF_KEY) {
+                               ref = (struct btrfs_root_ref *)(args.buf + off);
+                               name_len = btrfs_stack_root_ref_name_len(ref);
+                               name = (char *)(ref + 1);
+                               dir_id = btrfs_stack_root_ref_dirid(ref);
+                               tmppath = get_btrfs_subvol_path(fd, sh.offset,
+                                               dir_id, name, name_len);
+                               if (!add_btrfs_tree_node(tree, sh.objectid,
+                                                       sh.offset, name,
+                                                       name_len, tmppath)) {
+                                       ERROR("Out of memory");
+                                       free_btrfs_tree(tree);
+                                       free(tmppath);
+                                       close(fd);
+                                       return -1;
+                               }
+                               free(tmppath);
+                       }
+                       off += sh.len;
+
+                       /*
+                        * record the mins in sk so we can make sure the
+                        * next search doesn't repeat this root
+                        */
+                       sk->min_objectid = sh.objectid;
+                       sk->min_type = sh.type;
+                       sk->min_offset = sh.offset;
+               }
+               sk->nr_items = 4096;
+               sk->min_offset++;
+               if (!sk->min_offset)
+                       sk->min_type++;
+               else
+                       continue;
+
+               if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) {
+                       sk->min_type = BTRFS_ROOT_ITEM_KEY;
+                       sk->min_objectid++;
+               } else
+                       continue;
+
+               if (sk->min_objectid >= sk->max_objectid)
+                       break;
+       }
+       close(fd);
+
+       /* now actually remove them */
+
+       if (!do_remove_btrfs_children(tree, root_id, path)) {
+               free_btrfs_tree(tree);
+               ERROR("failed pruning\n");
+               return -1;
+       }
+
+       free_btrfs_tree(tree);
+       /* All child subvols have been removed, now remove this one */
+ignore_search:
+       return btrfs_do_destroy_subvol(path);
+}
+
+bool btrfs_try_remove_subvol(const char *path)
+{
+       if (!btrfs_detect(path))
+               return false;
+       return btrfs_recursive_destroy(path) == 0;
+}
+
+int btrfs_destroy(struct bdev *orig)
+{
+       return btrfs_recursive_destroy(orig->src);
+}
+
+int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
+                struct bdev_specs *specs)
+{
+       bdev->src = strdup(dest);
+       bdev->dest = strdup(dest);
+       if (!bdev->src || !bdev->dest)
+               return -1;
+       return btrfs_subvolume_create(bdev->dest);
+}
+
similarity index 63%
rename from src/lxc/lxc-btrfs.h
rename to src/lxc/bdev/lxcbtrfs.h
index e263538..3b2742f 100644 (file)
@@ -1,3 +1,35 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_BTRFS_H
+#define __LXC_BTRFS_H
+
+#define _GNU_SOURCE
+#include <linux/types.h> /* __le64, __l32 ... */
+#include <stdbool.h>
+#include <stdint.h>
+#include <byteswap.h>
+
 typedef uint8_t u8;
 typedef uint16_t u16;
 typedef uint32_t u32;
@@ -12,7 +44,7 @@ struct btrfs_ioctl_space_info {
 struct btrfs_ioctl_space_args {
        unsigned long long space_slots;
        unsigned long long total_spaces;
-       struct btrfs_ioctl_space_info spaces[0];
+       struct btrfs_ioctl_space_info spaces[];
 };
 
 #define BTRFS_IOCTL_MAGIC 0x94
@@ -285,3 +317,95 @@ struct btrfs_ioctl_ino_lookup_args {
 #define BTRFS_FIRST_FREE_OBJECTID 256ULL
 #define BTRFS_LAST_FREE_OBJECTID -256ULL
 #define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
+
+/*
+ * The followings are macro for correctly getting member of
+ * structures in both low and big endian platforms as per
+ * btrfs-progs
+ */
+#ifdef __CHECKER__
+#define __force    __attribute__((force))
+#else
+#define __force
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le64(x) ((__force __le64)(u64)(bswap_64(x)))
+#define le64_to_cpu(x) ((__force u64)(__le64)(bswap_64(x)))
+#define cpu_to_le32(x) ((__force __le32)(u32)(bswap_32(x)))
+#define le32_to_cpu(x) ((__force u32)(__le32)(bswap_32(x)))
+#define cpu_to_le16(x) ((__force __le16)(u16)(bswap_16(x)))
+#define le16_to_cpu(x) ((__force u16)(__le16)(bswap_16(x)))
+#else
+#define cpu_to_le64(x) ((__force __le64)(u64)(x))
+#define le64_to_cpu(x) ((__force u64)(__le64)(x))
+#define cpu_to_le32(x) ((__force __le32)(u32)(x))
+#define le32_to_cpu(x) ((__force u32)(__le32)(x))
+#define cpu_to_le16(x) ((__force __le16)(u16)(x))
+#define le16_to_cpu(x) ((__force u16)(__le16)(x))
+#endif
+
+#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)              \
+static inline u##bits btrfs_##name(type *s)                             \
+{                                                                       \
+        return le##bits##_to_cpu(s->member);                            \
+}                                                                       \
+static inline void btrfs_set_##name(type *s, u##bits val)               \
+{                                                                       \
+        s->member = cpu_to_le##bits(val);                               \
+}
+
+/* defined as btrfs_stack_root_ref_dirid */
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
+/* defined as btrfs_stack_root_ref_sequence */
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
+/* defined as btrfs_stack_root_ref_name_len */
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+struct mytree_node {
+       u64 objid;
+       u64 parentid;
+       char *name;
+       char *dirname;
+};
+
+struct my_btrfs_tree {
+       struct mytree_node *nodes;
+       int num;
+};
+
+/*
+ * Functions associated with a btrfs bdev struct.
+ */
+int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+                    const char *cname, const char *oldpath,
+                    const char *lxcpath, int snap, uint64_t newsize,
+                    struct lxc_conf *conf);
+int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
+                struct bdev_specs *specs);
+int btrfs_destroy(struct bdev *orig);
+int btrfs_detect(const char *path);
+int btrfs_mount(struct bdev *bdev);
+int btrfs_umount(struct bdev *bdev);
+
+/*
+ * Helper functions
+ */
+char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name,
+                           int name_len);
+int btrfs_list_get_path_rootid(int fd, u64 *treeid);
+bool is_btrfs_fs(const char *path);
+bool btrfs_try_remove_subvol(const char *path);
+int btrfs_same_fs(const char *orig, const char *new);
+int btrfs_snapshot(const char *orig, const char *new);
+
+#endif // __LXC_BTRFS_H
diff --git a/src/lxc/bdev/lxcdir.c b/src/lxc/bdev/lxcdir.c
new file mode 100644 (file)
index 0000000..fb25840
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <string.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "utils.h"
+
+lxc_log_define(lxcdir, lxc);
+
+/*
+ * for a simple directory bind mount, we substitute the old container
+ * name and paths for the new
+ */
+int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       int len, ret;
+
+       if (snap) {
+               ERROR("directories cannot be snapshotted.  Try aufs or overlayfs.");
+               return -1;
+       }
+
+       if (!orig->dest || !orig->src)
+               return -1;
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+       new->src = malloc(len);
+       if (!new->src)
+               return -1;
+       ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return -1;
+       if ((new->dest = strdup(new->src)) == NULL)
+               return -1;
+
+       return 0;
+}
+
+int dir_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       if (specs && specs->dir)
+               bdev->src = strdup(specs->dir);
+       else
+               bdev->src = strdup(dest);
+       bdev->dest = strdup(dest);
+       if (!bdev->src || !bdev->dest) {
+               ERROR("Out of memory");
+               return -1;
+       }
+
+       if (mkdir_p(bdev->src, 0755) < 0) {
+               ERROR("Error creating %s", bdev->src);
+               return -1;
+       }
+       if (mkdir_p(bdev->dest, 0755) < 0) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int dir_destroy(struct bdev *orig)
+{
+       if (lxc_rmdir_onedev(orig->src, NULL) < 0)
+               return -1;
+       return 0;
+}
+
+int dir_detect(const char *path)
+{
+       if (strncmp(path, "dir:", 4) == 0)
+               return 1; // take their word for it
+       if (is_dir(path))
+               return 1;
+       return 0;
+}
+
+int dir_mount(struct bdev *bdev)
+{
+       unsigned long mntflags;
+       char *mntdata;
+       int ret;
+
+       if (strcmp(bdev->type, "dir"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return -22;
+       }
+
+       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+       free(mntdata);
+       return ret;
+}
+
+int dir_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "dir"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
diff --git a/src/lxc/bdev/lxcdir.h b/src/lxc/bdev/lxcdir.h
new file mode 100644 (file)
index 0000000..f5cca9a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_DIR_H
+#define __LXC_DIR_H
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with a dir bdev struct.
+ */
+int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int dir_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int dir_destroy(struct bdev *orig);
+int dir_detect(const char *path);
+int dir_mount(struct bdev *bdev);
+int dir_umount(struct bdev *bdev);
+
+#endif /* __LXC_DIR_H */
diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
new file mode 100644 (file)
index 0000000..c17483f
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <sys/types.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcloop.h"
+#include "utils.h"
+
+#ifndef LO_FLAGS_AUTOCLEAR
+#define LO_FLAGS_AUTOCLEAR 4
+#endif
+
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
+lxc_log_define(lxcloop, lxc);
+
+static int do_loop_create(const char *path, uint64_t size, const char *fstype);
+static int find_free_loopdev_no_control(int *retfd, char *namep);
+static int find_free_loopdev(int *retfd, char *namep);
+
+/*
+ * No idea what the original blockdev will be called, but the copy will be
+ * called $lxcpath/$lxcname/rootdev
+ */
+int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       char fstype[100];
+       uint64_t size = newsize;
+       int len, ret;
+       char *srcdev;
+
+       if (snap) {
+               ERROR("loop devices cannot be snapshotted.");
+               return -1;
+       }
+
+       if (!orig->dest || !orig->src)
+               return -1;
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3;
+       srcdev = alloca(len);
+       ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       new->src = malloc(len + 5);
+       if (!new->src)
+               return -1;
+       ret = snprintf(new->src, len + 5, "loop:%s", srcdev);
+       if (ret < 0 || ret >= len + 5)
+               return -1;
+
+       new->dest = malloc(len);
+       if (!new->dest)
+               return -1;
+       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       // it's tempting to say: if orig->src == loopback and !newsize, then
+       // copy the loopback file.  However, we'd have to make sure to
+       // correctly keep holes!  So punt for now.
+
+       if (is_blktype(orig)) {
+               if (!newsize && blk_getsize(orig, &size) < 0) {
+                       ERROR("Error getting size of %s", orig->src);
+                       return -1;
+               }
+               if (detect_fs(orig, fstype, 100) < 0) {
+                       INFO("could not find fstype for %s, using %s", orig->src,
+                               DEFAULT_FSTYPE);
+                       return -1;
+               }
+       } else {
+               sprintf(fstype, "%s", DEFAULT_FSTYPE);
+               if (!newsize)
+                       size = DEFAULT_FS_SIZE;
+       }
+       return do_loop_create(srcdev, size, fstype);
+}
+
+int loop_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       const char *fstype;
+       uint64_t sz;
+       int ret, len;
+       char *srcdev;
+
+       if (!specs)
+               return -1;
+
+       // dest is passed in as $lxcpath / $lxcname / rootfs
+       // srcdev will be:      $lxcpath / $lxcname / rootdev
+       // src will be 'loop:$srcdev'
+       len = strlen(dest) + 2;
+       srcdev = alloca(len);
+
+       ret = snprintf(srcdev, len, "%s", dest);
+       if (ret < 0 || ret >= len)
+               return -1;
+       sprintf(srcdev + len - 4, "dev");
+
+       bdev->src = malloc(len + 5);
+       if (!bdev->src)
+               return -1;
+       ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev);
+       if (ret < 0 || ret >= len + 5)
+               return -1;
+
+       sz = specs->fssize;
+       if (!sz)
+               sz = DEFAULT_FS_SIZE;
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+
+       if (!(bdev->dest = strdup(dest)))
+               return -1;
+
+       if (mkdir_p(bdev->dest, 0755) < 0) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return do_loop_create(srcdev, sz, fstype);
+}
+
+int loop_destroy(struct bdev *orig)
+{
+       return unlink(orig->src + 5);
+}
+
+int loop_detect(const char *path)
+{
+       if (strncmp(path, "loop:", 5) == 0)
+               return 1;
+       return 0;
+}
+
+int loop_mount(struct bdev *bdev)
+{
+       int lfd, ffd = -1, ret = -1;
+       struct loop_info64 lo;
+       char loname[100];
+
+       if (strcmp(bdev->type, "loop"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       if (find_free_loopdev(&lfd, loname) < 0)
+               return -22;
+
+       ffd = open(bdev->src + 5, O_RDWR);
+       if (ffd < 0) {
+               SYSERROR("Error opening backing file %s", bdev->src);
+               goto out;
+       }
+
+       if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) {
+               SYSERROR("Error attaching backing file to loop dev");
+               goto out;
+       }
+       memset(&lo, 0, sizeof(lo));
+       lo.lo_flags = LO_FLAGS_AUTOCLEAR;
+       if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) {
+               SYSERROR("Error setting autoclear on loop dev");
+               goto out;
+       }
+
+       ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
+       if (ret < 0)
+               ERROR("Error mounting %s", bdev->src);
+       else
+               bdev->lofd = lfd;
+
+out:
+       if (ffd > -1)
+               close(ffd);
+       if (ret < 0) {
+               close(lfd);
+               bdev->lofd = -1;
+       }
+       return ret;
+}
+
+int loop_umount(struct bdev *bdev)
+{
+       int ret;
+
+       if (strcmp(bdev->type, "loop"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       ret = umount(bdev->dest);
+       if (bdev->lofd >= 0) {
+               close(bdev->lofd);
+               bdev->lofd = -1;
+       }
+       return ret;
+}
+
+static int do_loop_create(const char *path, uint64_t size, const char *fstype)
+{
+       int fd, ret;
+       // create the new loopback file.
+       fd = creat(path, S_IRUSR|S_IWUSR);
+       if (fd < 0)
+               return -1;
+       if (lseek(fd, size, SEEK_SET) < 0) {
+               SYSERROR("Error seeking to set new loop file size");
+               close(fd);
+               return -1;
+       }
+       if (write(fd, "1", 1) != 1) {
+               SYSERROR("Error creating new loop file");
+               close(fd);
+               return -1;
+       }
+       ret = close(fd);
+       if (ret < 0) {
+               SYSERROR("Error closing new loop file");
+               return -1;
+       }
+
+       // create an fs in the loopback file
+       if (do_mkfs(path, fstype) < 0) {
+               ERROR("Error creating filesystem type %s on %s", fstype,
+                       path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int find_free_loopdev_no_control(int *retfd, char *namep)
+{
+       struct dirent dirent, *direntp;
+       struct loop_info64 lo;
+       DIR *dir;
+       int fd = -1;
+
+       dir = opendir("/dev");
+       if (!dir) {
+               SYSERROR("Error opening /dev");
+               return -1;
+       }
+       while (!readdir_r(dir, &dirent, &direntp)) {
+
+               if (!direntp)
+                       break;
+               if (strncmp(direntp->d_name, "loop", 4) != 0)
+                       continue;
+               fd = openat(dirfd(dir), direntp->d_name, O_RDWR);
+               if (fd < 0)
+                       continue;
+               if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) {
+                       close(fd);
+                       fd = -1;
+                       continue;
+               }
+               // We can use this fd
+               snprintf(namep, 100, "/dev/%s", direntp->d_name);
+               break;
+       }
+       closedir(dir);
+       if (fd == -1) {
+               ERROR("No loop device found");
+               return -1;
+       }
+
+       *retfd = fd;
+       return 0;
+}
+
+static int find_free_loopdev(int *retfd, char *namep)
+{
+       int rc, fd = -1;
+       int ctl = open("/dev/loop-control", O_RDWR);
+       if (ctl < 0)
+               return find_free_loopdev_no_control(retfd, namep);
+       rc = ioctl(ctl, LOOP_CTL_GET_FREE);
+       if (rc >= 0) {
+               snprintf(namep, 100, "/dev/loop%d", rc);
+               fd = open(namep, O_RDWR);
+       }
+       close(ctl);
+       if (fd == -1) {
+               ERROR("No loop device found");
+               return -1;
+       }
+       *retfd = fd;
+       return 0;
+}
diff --git a/src/lxc/bdev/lxcloop.h b/src/lxc/bdev/lxcloop.h
new file mode 100644 (file)
index 0000000..5d33182
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_LOOP_H
+#define __LXC_LOOP_H
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * functions associated with a loop bdev struct
+ */
+int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int loop_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int loop_destroy(struct bdev *orig);
+int loop_detect(const char *path);
+int loop_mount(struct bdev *bdev);
+int loop_umount(struct bdev *bdev);
+
+#endif /* __LXC_LOOP_H */
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
new file mode 100644 (file)
index 0000000..3d41b10
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
+#include <inttypes.h> /* Required for PRIu64 to work. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxclvm.h"
+#include "utils.h"
+
+lxc_log_define(lxclvm, lxc);
+
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+               const char *oldpath, const char *lxcpath);
+
+    /*
+     * LVM ops
+     */
+
+    /*
+     * path must be '/dev/$vg/$lv', $vg must be an existing VG, and $lv must not
+     * yet exist.  This function will attempt to create /dev/$vg/$lv of size
+     * $size. If thinpool is specified, we'll check for it's existence and if
+     * it's
+     * a valid thin pool, and if so, we'll create the requested lv from that
+     * thin
+     * pool.
+     */
+    static int do_lvm_create(const char *path, uint64_t size,
+                            const char *thinpool)
+{
+       int ret, pid, len;
+       char sz[24], *pathdup, *vg, *lv, *tp = NULL;
+
+       if ((pid = fork()) < 0) {
+               SYSERROR("failed fork");
+               return -1;
+       }
+       if (pid > 0)
+               return wait_for_pid(pid);
+
+       // specify bytes to lvcreate
+       ret = snprintf(sz, 24, "%"PRIu64"b", size);
+       if (ret < 0 || ret >= 24)
+               exit(EXIT_FAILURE);
+
+       pathdup = strdup(path);
+       if (!pathdup)
+               exit(EXIT_FAILURE);
+
+       lv = strrchr(pathdup, '/');
+       if (!lv)
+               exit(EXIT_FAILURE);
+
+       *lv = '\0';
+       lv++;
+
+       vg = strrchr(pathdup, '/');
+       if (!vg)
+               exit(EXIT_FAILURE);
+       vg++;
+
+       if (thinpool) {
+               len = strlen(pathdup) + strlen(thinpool) + 2;
+               tp = alloca(len);
+
+               ret = snprintf(tp, len, "%s/%s", pathdup, thinpool);
+               if (ret < 0 || ret >= len)
+                       exit(EXIT_FAILURE);
+
+               ret = lvm_is_thin_pool(tp);
+               INFO("got %d for thin pool at path: %s", ret, tp);
+               if (ret < 0)
+                       exit(EXIT_FAILURE);
+
+               if (!ret)
+                       tp = NULL;
+       }
+
+       if (!tp)
+           execlp("lvcreate", "lvcreate", "-L", sz, vg, "-n", lv, (char *)NULL);
+       else
+           execlp("lvcreate", "lvcreate", "--thinpool", tp, "-V", sz, vg, "-n", lv, (char *)NULL);
+
+       SYSERROR("execlp");
+       exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Look at /sys/dev/block/maj:min/dm/uuid.  If it contains the hardcoded LVM
+ * prefix "LVM-", then this is an lvm2 LV
+ */
+int lvm_detect(const char *path)
+{
+       char devp[MAXPATHLEN], buf[4];
+       FILE *fout;
+       int ret;
+       struct stat statbuf;
+
+       if (strncmp(path, "lvm:", 4) == 0)
+               return 1; // take their word for it
+
+       ret = stat(path, &statbuf);
+       if (ret != 0)
+               return 0;
+       if (!S_ISBLK(statbuf.st_mode))
+               return 0;
+
+       ret = snprintf(devp, MAXPATHLEN, "/sys/dev/block/%d:%d/dm/uuid",
+                       major(statbuf.st_rdev), minor(statbuf.st_rdev));
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("lvm uuid pathname too long");
+               return 0;
+       }
+       fout = fopen(devp, "r");
+       if (!fout)
+               return 0;
+       ret = fread(buf, 1, 4, fout);
+       fclose(fout);
+       if (ret != 4 || strncmp(buf, "LVM-", 4) != 0)
+               return 0;
+       return 1;
+}
+
+int lvm_mount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "lvm"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       /* if we might pass in data sometime, then we'll have to enrich
+        * mount_unknown_fs */
+       return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
+}
+
+int lvm_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "lvm"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
+
+int lvm_compare_lv_attr(const char *path, int pos, const char expected)
+{
+       struct lxc_popen_FILE *f;
+       int ret, len, status, start=0;
+       char *cmd, output[12];
+       const char *lvscmd = "lvs --unbuffered --noheadings -o lv_attr %s 2>/dev/null";
+
+       len = strlen(lvscmd) + strlen(path) - 1;
+       cmd = alloca(len);
+
+       ret = snprintf(cmd, len, lvscmd, path);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       f = lxc_popen(cmd);
+
+       if (f == NULL) {
+               SYSERROR("popen failed");
+               return -1;
+       }
+
+       ret = fgets(output, 12, f->f) == NULL;
+
+       status = lxc_pclose(f);
+
+       if (ret || WEXITSTATUS(status))
+               // Assume either vg or lvs do not exist, default
+               // comparison to false.
+               return 0;
+
+       len = strlen(output);
+       while(start < len && output[start] == ' ') start++;
+
+       if (start + pos < len && output[start + pos] == expected)
+               return 1;
+
+       return 0;
+}
+
+int lvm_is_thin_volume(const char *path)
+{
+       return lvm_compare_lv_attr(path, 6, 't');
+}
+
+int lvm_is_thin_pool(const char *path)
+{
+       return lvm_compare_lv_attr(path, 0, 't');
+}
+
+int lvm_snapshot(const char *orig, const char *path, uint64_t size)
+{
+       int ret, pid;
+       char sz[24], *pathdup, *lv;
+
+       if ((pid = fork()) < 0) {
+               SYSERROR("failed fork");
+               return -1;
+       }
+       if (pid > 0)
+               return wait_for_pid(pid);
+
+       // specify bytes to lvcreate
+       ret = snprintf(sz, 24, "%"PRIu64"b", size);
+       if (ret < 0 || ret >= 24)
+               exit(EXIT_FAILURE);
+
+       pathdup = strdup(path);
+       if (!pathdup)
+               exit(EXIT_FAILURE);
+       lv = strrchr(pathdup, '/');
+       if (!lv) {
+               free(pathdup);
+               exit(EXIT_FAILURE);
+       }
+       *lv = '\0';
+       lv++;
+
+       // check if the original lv is backed by a thin pool, in which case we
+       // cannot specify a size that's different from the original size.
+       ret = lvm_is_thin_volume(orig);
+       if (ret == -1) {
+               free(pathdup);
+               return -1;
+       }
+
+       if (!ret) {
+               ret = execlp("lvcreate", "lvcreate", "-s", "-L", sz, "-n", lv, orig, (char *)NULL);
+       } else {
+               ret = execlp("lvcreate", "lvcreate", "-s", "-n", lv, orig, (char *)NULL);
+       }
+
+       free(pathdup);
+       exit(EXIT_FAILURE);
+}
+
+int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath, int snap,
+               uint64_t newsize, struct lxc_conf *conf)
+{
+       char fstype[100];
+       uint64_t size = newsize;
+       int len, ret;
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       if (strcmp(orig->type, "lvm")) {
+               const char *vg;
+
+               if (snap) {
+                       ERROR("LVM snapshot from %s backing store is not supported",
+                               orig->type);
+                       return -1;
+               }
+               vg = lxc_global_config_value("lxc.bdev.lvm.vg");
+               len = strlen("/dev/") + strlen(vg) + strlen(cname) + 2;
+               if ((new->src = malloc(len)) == NULL)
+                       return -1;
+               ret = snprintf(new->src, len, "/dev/%s/%s", vg, cname);
+               if (ret < 0 || ret >= len)
+                       return -1;
+       } else {
+               new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath);
+               if (!new->src)
+                       return -1;
+       }
+
+       if (orig->mntopts) {
+               new->mntopts = strdup(orig->mntopts);
+               if (!new->mntopts)
+                       return -1;
+       }
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+       new->dest = malloc(len);
+       if (!new->dest)
+               return -1;
+       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return -1;
+       if (mkdir_p(new->dest, 0755) < 0)
+               return -1;
+
+       if (is_blktype(orig)) {
+               if (!newsize && blk_getsize(orig, &size) < 0) {
+                       ERROR("Error getting size of %s", orig->src);
+                       return -1;
+               }
+               if (detect_fs(orig, fstype, 100) < 0) {
+                       INFO("could not find fstype for %s, using ext3", orig->src);
+                       return -1;
+               }
+       } else {
+               sprintf(fstype, "ext3");
+               if (!newsize)
+                       size = DEFAULT_FS_SIZE;
+       }
+
+       if (snap) {
+               if (lvm_snapshot(orig->src, new->src, size) < 0) {
+                       ERROR("could not create %s snapshot of %s", new->src, orig->src);
+                       return -1;
+               }
+       } else {
+               if (do_lvm_create(new->src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) {
+                       ERROR("Error creating new lvm blockdev");
+                       return -1;
+               }
+               if (do_mkfs(new->src, fstype) < 0) {
+                       ERROR("Error creating filesystem type %s on %s", fstype,
+                               new->src);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int lvm_destroy(struct bdev *orig)
+{
+       pid_t pid;
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (!pid) {
+               execlp("lvremove", "lvremove", "-f", orig->src, (char *)NULL);
+               exit(EXIT_FAILURE);
+       }
+       return wait_for_pid(pid);
+}
+
+int lvm_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       const char *vg, *thinpool, *fstype, *lv = n;
+       uint64_t sz;
+       int ret, len;
+
+       if (!specs)
+               return -1;
+
+       vg = specs->lvm.vg;
+       if (!vg)
+               vg = lxc_global_config_value("lxc.bdev.lvm.vg");
+
+       thinpool = specs->lvm.thinpool;
+       if (!thinpool)
+               thinpool = lxc_global_config_value("lxc.bdev.lvm.thin_pool");
+
+       /* /dev/$vg/$lv */
+       if (specs->lvm.lv)
+               lv = specs->lvm.lv;
+
+       len = strlen(vg) + strlen(lv) + 7;
+       bdev->src = malloc(len);
+       if (!bdev->src)
+               return -1;
+
+       ret = snprintf(bdev->src, len, "/dev/%s/%s", vg, lv);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       // fssize is in bytes.
+       sz = specs->fssize;
+       if (!sz)
+               sz = DEFAULT_FS_SIZE;
+
+       if (do_lvm_create(bdev->src, sz, thinpool) < 0) {
+               ERROR("Error creating new lvm blockdev %s size %"PRIu64" bytes", bdev->src, sz);
+               return -1;
+       }
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+       if (do_mkfs(bdev->src, fstype) < 0) {
+               ERROR("Error creating filesystem type %s on %s", fstype,
+                       bdev->src);
+               return -1;
+       }
+       if (!(bdev->dest = strdup(dest)))
+               return -1;
+
+       if (mkdir_p(bdev->dest, 0755) < 0) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/bdev/lxclvm.h b/src/lxc/bdev/lxclvm.h
new file mode 100644 (file)
index 0000000..6f1a972
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_LVM_H
+#define __LXC_LVM_H
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with an lvm bdev struct.
+ */
+int lvm_detect(const char *path);
+int lvm_mount(struct bdev *bdev);
+int lvm_umount(struct bdev *bdev);
+int lvm_compare_lv_attr(const char *path, int pos, const char expected);
+int lvm_is_thin_volume(const char *path);
+int lvm_is_thin_pool(const char *path);
+int lvm_snapshot(const char *orig, const char *path, uint64_t size);
+int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath, int snap,
+               uint64_t newsize, struct lxc_conf *conf);
+int lvm_destroy(struct bdev *orig);
+int lvm_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+
+#endif /* __LXC_LVM_H */
diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c
new file mode 100644 (file)
index 0000000..8a320d2
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcnbd.h"
+#include "utils.h"
+
+lxc_log_define(lxcnbd, lxc);
+
+struct nbd_attach_data {
+       const char *nbd;
+       const char *path;
+};
+
+static bool clone_attach_nbd(const char *nbd, const char *path);
+static int do_attach_nbd(void *d);
+static bool nbd_busy(int idx);
+static void nbd_detach(const char *path);
+static int nbd_get_partition(const char *src);
+static bool wait_for_partition(const char *path);
+
+bool attach_nbd(char *src, struct lxc_conf *conf)
+{
+       char *orig = alloca(strlen(src)+1), *p, path[50];
+       int i = 0;
+
+       strcpy(orig, src);
+       /* if path is followed by a partition, drop that for now */
+       p = strchr(orig, ':');
+       if (p)
+               *p = '\0';
+       while (1) {
+               sprintf(path, "/dev/nbd%d", i);
+               if (!file_exists(path))
+                       return false;
+               if (nbd_busy(i)) {
+                       i++;
+                       continue;
+               }
+               if (!clone_attach_nbd(path, orig))
+                       return false;
+               conf->nbd_idx = i;
+               return true;
+       }
+}
+
+void detach_nbd_idx(int idx)
+{
+       int ret;
+       char path[50];
+
+       ret = snprintf(path, 50, "/dev/nbd%d", idx);
+       if (ret < 0 || ret >= 50)
+               return;
+
+       nbd_detach(path);
+}
+
+int nbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       return -ENOSYS;
+}
+
+int nbd_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       return -ENOSYS;
+}
+
+int nbd_destroy(struct bdev *orig)
+{
+       return -ENOSYS;
+}
+
+int nbd_detect(const char *path)
+{
+       if (strncmp(path, "nbd:", 4) == 0)
+               return 1;
+       return 0;
+}
+
+int nbd_mount(struct bdev *bdev)
+{
+       int ret = -1, partition;
+       char path[50];
+
+       if (strcmp(bdev->type, "nbd"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       /* nbd_idx should have been copied by bdev_init from the lxc_conf */
+       if (bdev->nbd_idx < 0)
+               return -22;
+       partition = nbd_get_partition(bdev->src);
+       if (partition)
+               ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
+                               partition);
+       else
+               ret = snprintf(path, 50, "/dev/nbd%d", bdev->nbd_idx);
+       if (ret < 0 || ret >= 50) {
+               ERROR("Error setting up nbd device path");
+               return ret;
+       }
+
+       /* It might take awhile for the partition files to show up */
+       if (partition) {
+               if (!wait_for_partition(path))
+                       return -2;
+       }
+       ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);
+       if (ret < 0)
+               ERROR("Error mounting %s", bdev->src);
+
+       return ret;
+}
+
+int nbd_umount(struct bdev *bdev)
+{
+       int ret;
+
+       if (strcmp(bdev->type, "nbd"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       ret = umount(bdev->dest);
+       return ret;
+}
+
+bool requires_nbd(const char *path)
+{
+       if (strncmp(path, "nbd:", 4) == 0)
+               return true;
+       return false;
+}
+
+static int do_attach_nbd(void *d)
+{
+       struct nbd_attach_data *data = d;
+       const char *nbd, *path;
+       pid_t pid;
+       sigset_t mask;
+       int sfd;
+       ssize_t s;
+       struct signalfd_siginfo fdsi;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGHUP);
+       sigaddset(&mask, SIGCHLD);
+
+       nbd = data->nbd;
+       path = data->path;
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
+               SYSERROR("Error blocking signals for nbd watcher");
+               exit(1);
+       }
+
+       sfd = signalfd(-1, &mask, 0);
+       if (sfd == -1) {
+               SYSERROR("Error opening signalfd for nbd task");
+               exit(1);
+       }
+
+       if (prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0) < 0)
+               SYSERROR("Error setting parent death signal for nbd watcher");
+
+       pid = fork();
+       if (pid) {
+               for (;;) {
+                       s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
+                       if (s != sizeof(struct signalfd_siginfo))
+                               SYSERROR("Error reading from signalfd");
+
+                       if (fdsi.ssi_signo == SIGHUP) {
+                               /* container has exited */
+                               nbd_detach(nbd);
+                               exit(0);
+                       } else if (fdsi.ssi_signo == SIGCHLD) {
+                               int status;
+                               /* If qemu-nbd fails, or is killed by a signal,
+                                * then exit */
+                               while (waitpid(-1, &status, WNOHANG) > 0) {
+                                       if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) ||
+                                                       WIFSIGNALED(status)) {
+                                               nbd_detach(nbd);
+                                               exit(1);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       close(sfd);
+       if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
+               WARN("Warning: unblocking signals for nbd watcher");
+
+       execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, (char *)NULL);
+       SYSERROR("Error executing qemu-nbd");
+       exit(1);
+}
+
+static bool clone_attach_nbd(const char *nbd, const char *path)
+{
+       pid_t pid;
+       struct nbd_attach_data data;
+
+       data.nbd = nbd;
+       data.path = path;
+
+       pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
+       if (pid < 0)
+               return false;
+       return true;
+}
+
+static bool nbd_busy(int idx)
+{
+       char path[100];
+       int ret;
+
+       ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);
+       if (ret < 0 || ret >= 100)
+               return true;
+       return file_exists(path);
+}
+
+static void nbd_detach(const char *path)
+{
+       int ret;
+       pid_t pid = fork();
+
+       if (pid < 0) {
+               SYSERROR("Error forking to detach nbd");
+               return;
+       }
+       if (pid) {
+               ret = wait_for_pid(pid);
+               if (ret < 0)
+                       ERROR("nbd disconnect returned an error");
+               return;
+       }
+       execlp("qemu-nbd", "qemu-nbd", "-d", path, (char *)NULL);
+       SYSERROR("Error executing qemu-nbd");
+       exit(1);
+}
+
+/*
+ * Pick the partition # off the end of a nbd:file:p
+ * description.  Return 1-9 for the partition id, or 0
+ * for no partition.
+ */
+static int nbd_get_partition(const char *src)
+{
+       char *p = strchr(src, ':');
+       if (!p)
+               return 0;
+       p = strchr(p+1, ':');
+       if (!p)
+               return 0;
+       p++;
+       if (*p < '1' || *p > '9')
+               return 0;
+       return *p - '0';
+}
+
+static bool wait_for_partition(const char *path)
+{
+       int count = 0;
+       while (count < 5) {
+               if (file_exists(path))
+                       return true;
+               sleep(1);
+               count++;
+       }
+       ERROR("Device %s did not show up after 5 seconds", path);
+       return false;
+}
diff --git a/src/lxc/bdev/lxcnbd.h b/src/lxc/bdev/lxcnbd.h
new file mode 100644 (file)
index 0000000..1404d5a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_NBD_H
+#define __LXC_NBD_H
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with an nbd bdev struct.
+ */
+int nbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int nbd_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int nbd_destroy(struct bdev *orig);
+int nbd_detect(const char *path);
+int nbd_mount(struct bdev *bdev);
+int nbd_umount(struct bdev *bdev);
+
+/* helpers */
+bool attach_nbd(char *src, struct lxc_conf *conf);
+void detach_nbd_idx(int idx);
+bool requires_nbd(const char *path);
+
+#endif /* __LXC_NBD_H */
diff --git a/src/lxc/bdev/lxcoverlay.c b/src/lxc/bdev/lxcoverlay.c
new file mode 100644 (file)
index 0000000..86181d9
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bdev.h"
+#include "conf.h"
+#include "confile.h"
+#include "log.h"
+#include "lxccontainer.h"
+#include "lxcoverlay.h"
+#include "lxcrsync.h"
+#include "utils.h"
+
+lxc_log_define(lxcoverlay, lxc);
+
+static char *ovl_name;
+
+/* defined in lxccontainer.c: needs to become common helper */
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+                         const char *oldpath, const char *lxcpath);
+
+static char *ovl_detect_name(void);
+static int ovl_do_rsync(struct bdev *orig, struct bdev *new,
+                       struct lxc_conf *conf);
+static int ovl_rsync(struct rsync_data *data);
+static int ovl_rsync_wrapper(void *data);
+
+int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+                  const char *cname, const char *oldpath, const char *lxcpath,
+                  int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       if (!snap) {
+               ERROR("overlayfs is only for snapshot clones");
+               return -22;
+       }
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
+       if (!new->dest)
+               return -1;
+       if (mkdir_p(new->dest, 0755) < 0)
+               return -1;
+
+       if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
+               WARN("Failed to update ownership of %s", new->dest);
+
+       if (strcmp(orig->type, "dir") == 0) {
+               char *delta, *lastslash;
+               char *work;
+               int ret, len, lastslashidx;
+
+               /*
+                * if we have
+                *      /var/lib/lxc/c2/rootfs
+                * then delta will be
+                *      /var/lib/lxc/c2/delta0
+                */
+               lastslash = strrchr(new->dest, '/');
+               if (!lastslash)
+                       return -22;
+               if (strlen(lastslash) < 7)
+                       return -22;
+               lastslash++;
+               lastslashidx = lastslash - new->dest;
+
+               delta = malloc(lastslashidx + 7);
+               if (!delta)
+                       return -1;
+               strncpy(delta, new->dest, lastslashidx + 1);
+               strcpy(delta + lastslashidx, "delta0");
+               if ((ret = mkdir(delta, 0755)) < 0) {
+                       SYSERROR("error: mkdir %s", delta);
+                       free(delta);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
+                       WARN("Failed to update ownership of %s", delta);
+
+               /*
+                * Make workdir for overlayfs.v22 or higher:
+                * The workdir will be
+                *      /var/lib/lxc/c2/olwork
+                * and is used to prepare files before they are atomically
+                * switched to the overlay destination. Workdirs need to be on
+                * the same filesystem as the upperdir so it's OK for it to be
+                * empty.
+                */
+               work = malloc(lastslashidx + 7);
+               if (!work) {
+                       free(delta);
+                       return -1;
+               }
+               strncpy(work, new->dest, lastslashidx + 1);
+               strcpy(work + lastslashidx, "olwork");
+               if (mkdir(work, 0755) < 0) {
+                       SYSERROR("error: mkdir %s", work);
+                       free(delta);
+                       free(work);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
+                       WARN("Failed to update ownership of %s", work);
+               free(work);
+
+               // the src will be 'overlayfs:lowerdir:upperdir'
+               len = strlen(delta) + strlen(orig->src) + 12;
+               new->src = malloc(len);
+               if (!new->src) {
+                       free(delta);
+                       return -ENOMEM;
+               }
+               ret = snprintf(new->src, len, "overlayfs:%s:%s", orig->src, delta);
+               free(delta);
+               if (ret < 0 || ret >= len)
+                       return -ENOMEM;
+       } else if (strcmp(orig->type, "overlayfs") == 0) {
+               /*
+                * What exactly do we want to do here?  I think we want to use
+                * the original lowerdir, with a private delta which is
+                * originally rsynced from the original delta
+                */
+               char *osrc, *odelta, *nsrc, *ndelta, *work;
+               char *lastslash;
+               int len, ret, lastslashidx;
+               if (!(osrc = strdup(orig->src)))
+                       return -22;
+               nsrc = strchr(osrc, ':') + 1;
+               if (nsrc != osrc + 10 || (odelta = strchr(nsrc, ':')) == NULL) {
+                       free(osrc);
+                       return -22;
+               }
+               *odelta = '\0';
+               odelta++;
+               ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
+               if (!ndelta) {
+                       free(osrc);
+                       return -ENOMEM;
+               }
+               if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
+                       SYSERROR("error: mkdir %s", ndelta);
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
+                       WARN("Failed to update ownership of %s", ndelta);
+
+               /*
+                * make workdir for overlayfs.v22 or higher (see comment further
+                * up)
+                */
+               lastslash = strrchr(ndelta, '/');
+               if (!lastslash) {
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+               lastslash++;
+               lastslashidx = lastslash - ndelta;
+
+               work = malloc(lastslashidx + 7);
+               if (!work) {
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+               strncpy(work, ndelta, lastslashidx + 1);
+               strcpy(work + lastslashidx, "olwork");
+               if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
+                       SYSERROR("error: mkdir %s", work);
+                       free(osrc);
+                       free(ndelta);
+                       free(work);
+                       return -1;
+               }
+               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
+                       WARN("Failed to update ownership of %s", work);
+               free(work);
+
+               len = strlen(nsrc) + strlen(ndelta) + 12;
+               new->src = malloc(len);
+               if (!new->src) {
+                       free(osrc);
+                       free(ndelta);
+                       return -ENOMEM;
+               }
+               ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
+               free(osrc);
+               free(ndelta);
+               if (ret < 0 || ret >= len)
+                       return -ENOMEM;
+
+               return ovl_do_rsync(orig, new, conf);
+       } else {
+               ERROR("overlayfs clone of %s container is not yet supported",
+                     orig->type);
+               /*
+                * Note, supporting this will require ovl_mount supporting
+                * mounting of the underlay. No big deal, just needs to be done.
+                */
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * to say 'lxc-create -t ubuntu -n o1 -B overlayfs' means you want
+ * $lxcpath/$lxcname/rootfs to have the created container, while all
+ * changes after starting the container are written to
+ * $lxcpath/$lxcname/delta0
+ */
+int ovl_create(struct bdev *bdev, const char *dest, const char *n,
+                       struct bdev_specs *specs)
+{
+       char *delta;
+       int ret, len = strlen(dest), newlen;
+
+       if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0)
+               return -1;
+
+       if (!(bdev->dest = strdup(dest))) {
+               ERROR("Out of memory");
+               return -1;
+       }
+
+       delta = alloca(strlen(dest) + 1);
+       strcpy(delta, dest);
+       strcpy(delta + len - 6, "delta0");
+
+       if (mkdir_p(delta, 0755) < 0) {
+               ERROR("Error creating %s", delta);
+               return -1;
+       }
+
+       // overlayfs:lower:upper
+       newlen = (2 * len) + strlen("overlayfs:") + 2;
+       bdev->src = malloc(newlen);
+       if (!bdev->src) {
+               ERROR("Out of memory");
+               return -1;
+       }
+       ret = snprintf(bdev->src, newlen, "overlayfs:%s:%s", dest, delta);
+       if (ret < 0 || ret >= newlen)
+               return -1;
+
+       if (mkdir_p(bdev->dest, 0755) < 0) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int ovl_destroy(struct bdev *orig)
+{
+       char *upper;
+
+       if (strncmp(orig->src, "overlayfs:", 10) != 0)
+               return -22;
+       upper = strchr(orig->src + 10, ':');
+       if (!upper)
+               return -22;
+       upper++;
+       return lxc_rmdir_onedev(upper, NULL);
+}
+
+int ovl_detect(const char *path)
+{
+       if (strncmp(path, "overlayfs:", 10) == 0)
+               return 1; // take their word for it
+       return 0;
+}
+
+char *ovl_getlower(char *p)
+{
+       char *p1 = strchr(p, ':');
+       if (p1)
+               *p1 = '\0';
+       return p;
+}
+
+int ovl_mount(struct bdev *bdev)
+{
+       char *tmp, *options, *dup, *lower, *upper;
+       char *options_work, *work, *lastslash;
+       int lastslashidx;
+       int len, len2;
+       unsigned long mntflags;
+       char *mntdata;
+       int ret, ret2;
+
+       if (strcmp(bdev->type, "overlayfs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       if (!ovl_name)
+               ovl_name = ovl_detect_name();
+
+       /*
+        * separately mount it first:
+        * mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest
+        */
+       dup = alloca(strlen(bdev->src) + 1);
+       strcpy(dup, bdev->src);
+       /* support multiple lower layers */
+       if (!(lower = strstr(dup, ":/")))
+                       return -22;
+       lower++;
+       upper = lower;
+       while ((tmp = strstr(++upper, ":/"))) {
+               upper = tmp;
+       }
+       if (--upper == lower)
+               return -22;
+       *upper = '\0';
+       upper++;
+
+       // if delta doesn't yet exist, create it
+       if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
+               return -22;
+
+       /*
+        * overlayfs.v22 or higher needs workdir option:
+        * if upper is
+        *      /var/lib/lxc/c2/delta0
+        * then workdir is
+        *      /var/lib/lxc/c2/olwork
+        */
+       lastslash = strrchr(upper, '/');
+       if (!lastslash)
+               return -22;
+       lastslash++;
+       lastslashidx = lastslash - upper;
+
+       work = alloca(lastslashidx + 7);
+       strncpy(work, upper, lastslashidx + 7);
+       strcpy(work + lastslashidx, "olwork");
+
+       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return -22;
+       }
+
+       if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
+               free(mntdata);
+               return -22;
+       }
+
+       /*
+        * TODO:
+        * We should check whether bdev->src is a blockdev but for now only
+        * support overlays of a basic directory
+        */
+
+       if (mntdata) {
+               len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
+               options = alloca(len);
+               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
+
+               len2 = strlen(lower) + strlen(upper) + strlen(work)
+                       + strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
+               options_work = alloca(len2);
+               ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
+                               upper, lower, work, mntdata);
+       } else {
+               len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
+               options = alloca(len);
+               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
+
+               len2 = strlen(lower) + strlen(upper) + strlen(work)
+                       + strlen("upperdir=,lowerdir=,workdir=") + 1;
+               options_work = alloca(len2);
+               ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
+                       upper, lower, work);
+       }
+
+       if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
+               free(mntdata);
+               return -1;
+       }
+
+       // mount without workdir option for overlayfs before v21
+       ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options);
+       if (ret < 0) {
+               INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
+                       lower, bdev->dest, options);
+
+               // retry with workdir option for overlayfs v22 and higher
+               ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work);
+               if (ret < 0)
+                       SYSERROR("overlayfs: error mounting %s onto %s options %s",
+                               lower, bdev->dest, options_work);
+               else
+                       INFO("overlayfs: mounted %s onto %s options %s",
+                               lower, bdev->dest, options_work);
+       } else {
+               INFO("overlayfs: mounted %s onto %s options %s",
+                       lower, bdev->dest, options);
+       }
+       return ret;
+}
+
+int ovl_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "overlayfs"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
+
+char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
+{
+       char *rootfsdir = NULL;
+       char *s1 = NULL;
+       char *s2 = NULL;
+       char *s3 = NULL;
+
+       if (!rootfs_path || !rootfslen)
+               return NULL;
+
+       s1 = strdup(rootfs_path);
+       if (!s1)
+               return NULL;
+
+       if ((s2 = strstr(s1, ":/"))) {
+               s2 = s2 + 1;
+               if ((s3 = strstr(s2, ":/")))
+                       *s3 = '\0';
+               rootfsdir = strdup(s2);
+               if (!rootfsdir) {
+                       free(s1);
+                       return NULL;
+               }
+       }
+
+       if (!rootfsdir)
+               rootfsdir = s1;
+       else
+               free(s1);
+
+       *rootfslen = strlen(rootfsdir);
+
+       return rootfsdir;
+}
+
+int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
+             const char *lxc_name, const char *lxc_path)
+{
+       char lxcpath[MAXPATHLEN];
+       char *rootfs_path = NULL;
+       char *rootfsdir = NULL;
+       char *upperdir = NULL;
+       char *workdir = NULL;
+       char **opts = NULL;
+       int fret = -1;
+       int ret = 0;
+       size_t arrlen = 0;
+       size_t dirlen = 0;
+       size_t i;
+       size_t len = 0;
+       size_t rootfslen = 0;
+
+       /* When rootfs == NULL we have a container without a rootfs. */
+       if (rootfs && rootfs->path)
+               rootfs_path = rootfs->path;
+
+       opts = lxc_string_split(mntent->mnt_opts, ',');
+       if (opts)
+               arrlen = lxc_array_len((void **)opts);
+       else
+               goto err;
+
+       for (i = 0; i < arrlen; i++) {
+               if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
+                       upperdir = opts[i] + len;
+               else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
+                       workdir = opts[i] + len;
+       }
+
+       if (rootfs_path) {
+               ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       goto err;
+
+               rootfsdir = ovl_get_rootfs(rootfs_path, &rootfslen);
+               if (!rootfsdir)
+                       goto err;
+
+               dirlen = strlen(lxcpath);
+       }
+
+       /*
+        * We neither allow users to create upperdirs and workdirs outside the
+        * containerdir nor inside the rootfs. The latter might be debatable.
+        * When we have a container without a rootfs we skip the checks.
+        */
+       ret = 0;
+       if (upperdir) {
+               if (!rootfs_path)
+                       ret = mkdir_p(upperdir, 0755);
+               else if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
+                       ret = mkdir_p(upperdir, 0755);
+               if (ret < 0)
+                       WARN("Failed to create upperdir");
+       }
+
+       ret = 0;
+       if (workdir) {
+               if (!rootfs_path)
+                       ret = mkdir_p(workdir, 0755);
+               else if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
+                       ret = mkdir_p(workdir, 0755);
+               if (ret < 0)
+                       WARN("Failed to create workdir");
+       }
+
+       fret = 0;
+
+err:
+       free(rootfsdir);
+       lxc_free_array((void **)opts, free);
+       return fret;
+}
+
+/*
+ * To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
+ * with overlay lxc.mount.entry entries we need to update absolute paths for
+ * upper- and workdir. This update is done in two locations:
+ * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
+ * independent of each other since lxc_conf->mountlist may container more mount
+ * entries (e.g. from other included files) than lxc_conf->unexpanded_config .
+ */
+int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
+                        const char *lxc_name, const char *newpath,
+                        const char *newname)
+{
+       char new_upper[MAXPATHLEN];
+       char new_work[MAXPATHLEN];
+       char old_upper[MAXPATHLEN];
+       char old_work[MAXPATHLEN];
+       char *cleanpath = NULL;
+       int i;
+       int fret = -1;
+       int ret = 0;
+       struct lxc_list *iterator;
+       const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
+
+       cleanpath = strdup(newpath);
+       if (!cleanpath)
+               goto err;
+
+       remove_trailing_slashes(cleanpath);
+
+       /*
+        * We have to update lxc_conf->unexpanded_config separately from
+        * lxc_conf->mount_list.
+        */
+       for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
+               if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
+                                                 lxc_name, newname,
+                                                 ovl_dirs[i]))
+                       goto err;
+       }
+
+       ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               goto err;
+
+       ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               goto err;
+
+       lxc_list_for_each(iterator, &lxc_conf->mount_list) {
+               char *mnt_entry = NULL;
+               char *new_mnt_entry = NULL;
+               char *tmp = NULL;
+               char *tmp_mnt_entry = NULL;
+               mnt_entry = iterator->elem;
+
+               if (strstr(mnt_entry, "overlay"))
+                       tmp = "upperdir";
+               else if (strstr(mnt_entry, "aufs"))
+                       tmp = "br";
+
+               if (!tmp)
+                       continue;
+
+               ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       goto err;
+
+               ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       goto err;
+
+               if (strstr(mnt_entry, old_upper)) {
+                       tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
+               }
+
+               if (strstr(mnt_entry, old_work)) {
+                       if (tmp_mnt_entry)
+                               new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry);
+                       else
+                               new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry);
+               }
+
+               if (new_mnt_entry) {
+                       free(iterator->elem);
+                       iterator->elem = strdup(new_mnt_entry);
+               } else if (tmp_mnt_entry) {
+                       free(iterator->elem);
+                       iterator->elem = strdup(tmp_mnt_entry);
+               }
+
+               free(new_mnt_entry);
+               free(tmp_mnt_entry);
+       }
+
+       fret = 0;
+err:
+       free(cleanpath);
+       return fret;
+}
+
+static int ovl_rsync(struct rsync_data *data)
+{
+       int ret;
+
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+
+       if (unshare(CLONE_NEWNS) < 0) {
+               SYSERROR("Unable to unshare mounts ns");
+               return -1;
+       }
+       if (detect_shared_rootfs()) {
+               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+                       SYSERROR("Failed to make / rslave");
+                       ERROR("Continuing...");
+               }
+       }
+       if (ovl_mount(data->orig) < 0) {
+               ERROR("Failed mounting original container fs");
+               return -1;
+       }
+       if (ovl_mount(data->new) < 0) {
+               ERROR("Failed mounting new container fs");
+               return -1;
+       }
+       ret = do_rsync(data->orig->dest, data->new->dest);
+
+       ovl_umount(data->new);
+       ovl_umount(data->orig);
+
+       if (ret < 0) {
+               ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+static char *ovl_detect_name(void)
+{
+       char *v = "overlayfs";
+       char *line = NULL;
+       size_t len = 0;
+       FILE *f = fopen("/proc/filesystems", "r");
+       if (!f)
+               return v;
+
+       while (getline(&line, &len, f) != -1) {
+               if (strcmp(line, "nodev\toverlay\n") == 0) {
+                       v = "overlay";
+                       break;
+               }
+       }
+
+       fclose(f);
+       free(line);
+       return v;
+}
+
+static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
+{
+       int ret = -1;
+       struct rsync_data rdata;
+
+       rdata.orig = orig;
+       rdata.new = new;
+       if (am_unpriv())
+               ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
+       else
+               ret = ovl_rsync(&rdata);
+       if (ret)
+               ERROR("copying overlayfs delta");
+
+       return ret;
+}
+
+static int ovl_rsync_wrapper(void *data)
+{
+       struct rsync_data *arg = data;
+       return ovl_rsync(arg);
+}
+
diff --git a/src/lxc/bdev/lxcoverlay.h b/src/lxc/bdev/lxcoverlay.h
new file mode 100644 (file)
index 0000000..8ef277b
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_OVERLAY_H
+#define __LXC_OVERLAY_H
+
+#include <grp.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#if IS_BIONIC
+#include <../include/lxcmntent.h>
+#else
+#include <mntent.h>
+#endif
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/* defined in conf.h */
+struct lxc_rootfs;
+
+/*
+ * Functions associated with an overlay bdev struct.
+ */
+int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+                  const char *cname, const char *oldpath, const char *lxcpath,
+                  int snap, uint64_t newsize, struct lxc_conf *conf);
+int ovl_create(struct bdev *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs);
+int ovl_destroy(struct bdev *orig);
+int ovl_detect(const char *path);
+int ovl_mount(struct bdev *bdev);
+int ovl_umount(struct bdev *bdev);
+
+/*
+ * To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
+ * with overlay lxc.mount.entry entries we need to update absolute paths for
+ * upper- and workdir. This update is done in two locations:
+ * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
+ * independent of each other since lxc_conf->mountlist may container more mount
+ * entries (e.g. from other included files) than lxc_conf->unexpanded_config .
+ */
+int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
+                        const char *lxc_name, const char *newpath,
+                        const char *newname);
+
+/*
+ * To be called from functions in lxccontainer.c: Get lower directory for
+ * overlay rootfs.
+ */
+char *ovl_getlower(char *p);
+
+/*
+ * Get rootfs path for overlay backed containers. Allocated memory must be freed
+ * by caller.
+ */
+char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen);
+
+/*
+ * Create upper- and workdirs for overlay mounts.
+ */
+int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
+             const char *lxc_name, const char *lxc_path);
+
+#endif /* __LXC_OVERLAY_H */
diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c
new file mode 100644 (file)
index 0000000..8e3a452
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
+#include <inttypes.h> /* Required for PRIu64 to work. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "utils.h"
+
+lxc_log_define(lxcrbd, lxc);
+
+int rbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       ERROR("rbd clonepaths not implemented");
+       return -1;
+}
+
+int rbd_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       const char *rbdpool, *rbdname = n, *fstype;
+       uint64_t size;
+       int ret, len;
+       char sz[24];
+       pid_t pid;
+
+       if (!specs)
+               return -1;
+
+       rbdpool = specs->rbd.rbdpool;
+       if (!rbdpool)
+               rbdpool = lxc_global_config_value("lxc.bdev.rbd.rbdpool");
+
+       if (specs->rbd.rbdname)
+               rbdname = specs->rbd.rbdname;
+
+       /* source device /dev/rbd/lxc/ctn */
+       len = strlen(rbdpool) + strlen(rbdname) + 11;
+       bdev->src = malloc(len);
+       if (!bdev->src)
+               return -1;
+
+       ret = snprintf(bdev->src, len, "/dev/rbd/%s/%s", rbdpool, rbdname);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       // fssize is in bytes.
+       size = specs->fssize;
+       if (!size)
+               size = DEFAULT_FS_SIZE;
+
+       // in megabytes for rbd tool
+       ret = snprintf(sz, 24, "%"PRIu64, size / 1024 / 1024 );
+       if (ret < 0 || ret >= 24)
+               exit(1);
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (!pid) {
+               execlp("rbd", "rbd", "create" , "--pool", rbdpool, rbdname, "--size", sz, (char *)NULL);
+               exit(1);
+       }
+       if (wait_for_pid(pid) < 0)
+               return -1;
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (!pid) {
+               execlp("rbd", "rbd", "map", "--pool", rbdpool, rbdname, (char *)NULL);
+               exit(1);
+       }
+       if (wait_for_pid(pid) < 0)
+               return -1;
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+
+       if (do_mkfs(bdev->src, fstype) < 0) {
+               ERROR("Error creating filesystem type %s on %s", fstype,
+                       bdev->src);
+               return -1;
+       }
+       if (!(bdev->dest = strdup(dest)))
+               return -1;
+
+       if (mkdir_p(bdev->dest, 0755) < 0 && errno != EEXIST) {
+               ERROR("Error creating %s", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rbd_destroy(struct bdev *orig)
+{
+       pid_t pid;
+       char *rbdfullname;
+
+       if ( file_exists(orig->src) ) {
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("rbd", "rbd", "unmap" , orig->src, (char *)NULL);
+                       exit(1);
+               }
+               if (wait_for_pid(pid) < 0)
+                       return -1;
+       }
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (!pid) {
+               rbdfullname = alloca(strlen(orig->src) - 8);
+               strcpy( rbdfullname, &orig->src[9] );
+               execlp("rbd", "rbd", "rm" , rbdfullname, (char *)NULL);
+               exit(1);
+       }
+       return wait_for_pid(pid);
+
+}
+
+int rbd_detect(const char *path)
+{
+       if ( memcmp(path, "/dev/rbd/", 9) == 0)
+               return 1;
+       return 0;
+}
+
+int rbd_mount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "rbd"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       if ( !file_exists(bdev->src) ) {
+               // if blkdev does not exist it should be mapped, because it is not persistent on reboot
+               ERROR("Block device %s is not mapped.", bdev->src);
+               return -1;
+       }
+
+       return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
+}
+
+int rbd_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "rbd"))
+               return -22;
+       if (!bdev->src || !bdev->dest)
+               return -22;
+       return umount(bdev->dest);
+}
diff --git a/src/lxc/bdev/lxcrbd.h b/src/lxc/bdev/lxcrbd.h
new file mode 100644 (file)
index 0000000..19fa026
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_RDB_H
+#define __LXC_RDB_H
+
+#define _GNU_SOURCE
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with an rdb bdev struct.
+ */
+int rbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int rbd_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int rbd_destroy(struct bdev *orig);
+int rbd_detect(const char *path);
+int rbd_mount(struct bdev *bdev);
+int rbd_umount(struct bdev *bdev);
+
+#endif /* __LXC_RDB_H */
diff --git a/src/lxc/bdev/lxcrsync.c b/src/lxc/bdev/lxcrsync.c
new file mode 100644 (file)
index 0000000..17f0b6e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <grp.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcrsync.h"
+#include "utils.h"
+
+lxc_log_define(lxcrsync, lxc);
+
+/* the bulk of this needs to become a common helper */
+int do_rsync(const char *src, const char *dest)
+{
+       // call out to rsync
+       pid_t pid;
+       char *s;
+       size_t l;
+
+       pid = fork();
+       if (pid < 0)
+               return -1;
+       if (pid > 0)
+               return wait_for_pid(pid);
+
+       l = strlen(src) + 2;
+       s = malloc(l);
+       if (!s)
+               exit(1);
+       strcpy(s, src);
+       s[l-2] = '/';
+       s[l-1] = '\0';
+
+       execlp("rsync", "rsync", "-aHX", "--delete", s, dest, (char *)NULL);
+       exit(1);
+}
+
+int rsync_delta(struct rsync_data_char *data)
+{
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+       if (do_rsync(data->src, data->dest) < 0) {
+               ERROR("rsyncing %s to %s", data->src, data->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rsync_delta_wrapper(void *data)
+{
+       struct rsync_data_char *arg = data;
+       return rsync_delta(arg);
+}
+
+int rsync_rootfs(struct rsync_data *data)
+{
+       struct bdev *orig = data->orig,
+                   *new = data->new;
+
+       if (unshare(CLONE_NEWNS) < 0) {
+               SYSERROR("unshare CLONE_NEWNS");
+               return -1;
+       }
+       if (detect_shared_rootfs()) {
+               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+                       SYSERROR("Failed to make / rslave");
+                       ERROR("Continuing...");
+               }
+       }
+
+       // If not a snapshot, copy the fs.
+       if (orig->ops->mount(orig) < 0) {
+               ERROR("failed mounting %s onto %s", orig->src, orig->dest);
+               return -1;
+       }
+       if (new->ops->mount(new) < 0) {
+               ERROR("failed mounting %s onto %s", new->src, new->dest);
+               return -1;
+       }
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+       if (do_rsync(orig->dest, new->dest) < 0) {
+               ERROR("rsyncing %s to %s", orig->src, new->src);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rsync_rootfs_wrapper(void *data)
+{
+       struct rsync_data *arg = data;
+       return rsync_rootfs(arg);
+}
+
diff --git a/src/lxc/bdev/lxcrsync.h b/src/lxc/bdev/lxcrsync.h
new file mode 100644 (file)
index 0000000..802a885
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_RSYNC_H
+#define __LXC_RSYNC_H
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+struct rsync_data {
+       struct bdev *orig;
+       struct bdev *new;
+};
+
+struct rsync_data_char {
+       char *src;
+       char *dest;
+};
+
+int do_rsync(const char *src, const char *dest);
+int rsync_delta_wrapper(void *data);
+int rsync_delta(struct rsync_data_char *data);
+int rsync_rootfs(struct rsync_data *data);
+int rsync_rootfs_wrapper(void *data);
+
+#endif // __LXC_RSYNC_H
diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c
new file mode 100644 (file)
index 0000000..dd1005b
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+
+#include "bdev.h"
+#include "config.h"
+#include "log.h"
+#include "lxczfs.h"
+#include "utils.h"
+
+lxc_log_define(lxczfs, lxc);
+
+/*
+ * zfs ops:
+ * There are two ways we could do this. We could always specify the 'zfs device'
+ * (i.e. tank/lxc lxc/container) as rootfs. But instead (at least right now) we
+ * have lxc-create specify $lxcpath/$lxcname/rootfs as the mountpoint, so that
+ * it is always mounted. That means 'mount' is really never needed and could be
+ * noop, but for the sake of flexibility let's always bind-mount.
+ */
+
+int zfs_list_entry(const char *path, char *output, size_t inlen)
+{
+       struct lxc_popen_FILE *f;
+       int found=0;
+
+       f = lxc_popen("zfs list 2> /dev/null");
+       if (f == NULL) {
+               SYSERROR("popen failed");
+               return 0;
+       }
+
+       while (fgets(output, inlen, f->f)) {
+               if (strstr(output, path)) {
+                       found = 1;
+                       break;
+               }
+       }
+       (void) lxc_pclose(f);
+
+       return found;
+}
+
+int zfs_detect(const char *path)
+{
+       char *output = malloc(LXC_LOG_BUFFER_SIZE);
+
+       if (!output) {
+               ERROR("out of memory");
+               return 0;
+       }
+
+       int found = zfs_list_entry(path, output, LXC_LOG_BUFFER_SIZE);
+       free(output);
+
+       return found;
+}
+
+int zfs_mount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "zfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       char *mntdata;
+       unsigned long mntflags;
+       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+               free(mntdata);
+               return -22;
+       }
+
+       int ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+       free(mntdata);
+
+       return ret;
+}
+
+int zfs_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "zfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       return umount(bdev->dest);
+}
+
+int zfs_clone(const char *opath, const char *npath, const char *oname,
+               const char *nname, const char *lxcpath, int snapshot)
+{
+       // use the 'zfs list | grep opath' entry to get the zfsroot
+       char output[MAXPATHLEN], option[MAXPATHLEN];
+       char *p;
+       const char *zfsroot = output;
+       int ret;
+       pid_t pid;
+
+       if (zfs_list_entry(opath, output, MAXPATHLEN)) {
+               // zfsroot is output up to ' '
+               if ((p = strchr(output, ' ')) == NULL)
+                       return -1;
+               *p = '\0';
+
+               if ((p = strrchr(output, '/')) == NULL)
+                       return -1;
+               *p = '\0';
+       } else {
+               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
+       }
+
+       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs", lxcpath, nname);
+       if (ret < 0  || ret >= MAXPATHLEN)
+               return -1;
+
+       // zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname
+       if (!snapshot) {
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       char dev[MAXPATHLEN];
+                       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname);
+                       if (ret < 0  || ret >= MAXPATHLEN)
+                               exit(EXIT_FAILURE);
+                       execlp("zfs", "zfs", "create", option, dev, (char *)NULL);
+                       exit(EXIT_FAILURE);
+               }
+               return wait_for_pid(pid);
+       } else {
+               // if snapshot, do
+               // 'zfs snapshot zfsroot/oname@nname
+               // zfs clone zfsroot/oname@nname zfsroot/nname
+               char path1[MAXPATHLEN], path2[MAXPATHLEN];
+
+               ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", zfsroot,
+                               oname, nname);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       return -1;
+               (void) snprintf(path2, MAXPATHLEN, "%s/%s", zfsroot, nname);
+
+               // if the snapshot exists, delete it
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "destroy", path1, (char *)NULL);
+                       exit(EXIT_FAILURE);
+               }
+               // it probably doesn't exist so destroy probably will fail.
+               (void) wait_for_pid(pid);
+
+               // run first (snapshot) command
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "snapshot", path1, (char *)NULL);
+                       exit(EXIT_FAILURE);
+               }
+               if (wait_for_pid(pid) < 0)
+                       return -1;
+
+               // run second (clone) command
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "clone", option, path1, path2, (char *)NULL);
+                       exit(EXIT_FAILURE);
+               }
+               return wait_for_pid(pid);
+       }
+}
+
+int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath, int snap,
+               uint64_t newsize, struct lxc_conf *conf)
+{
+       int len, ret;
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       if (snap && strcmp(orig->type, "zfs")) {
+               ERROR("zfs snapshot from %s backing store is not supported", orig->type);
+               return -1;
+       }
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+       new->src = malloc(len);
+       if (!new->src)
+               return -1;
+
+       ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return -1;
+
+       if ((new->dest = strdup(new->src)) == NULL)
+               return -1;
+
+       return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
+}
+
+/*
+ * TODO: detect whether this was a clone, and if so then also delete the
+ * snapshot it was based on, so that we don't hold the original
+ * container busy.
+ */
+int zfs_destroy(struct bdev *orig)
+{
+       pid_t pid;
+       char output[MAXPATHLEN];
+       char *p;
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (pid)
+               return wait_for_pid(pid);
+
+       if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
+               ERROR("Error: zfs entry for %s not found", orig->src);
+               return -1;
+       }
+
+       // zfs mount is output up to ' '
+       if ((p = strchr(output, ' ')) == NULL)
+               return -1;
+       *p = '\0';
+
+       execlp("zfs", "zfs", "destroy", output, (char *)NULL);
+       exit(EXIT_FAILURE);
+}
+
+int zfs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       const char *zfsroot;
+       char option[MAXPATHLEN];
+       int ret;
+       pid_t pid;
+
+       if (!specs || !specs->zfs.zfsroot)
+               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
+       else
+               zfsroot = specs->zfs.zfsroot;
+
+       if (!(bdev->dest = strdup(dest))) {
+               ERROR("No mount target specified or out of memory");
+               return -1;
+       }
+       if (!(bdev->src = strdup(bdev->dest))) {
+               ERROR("out of memory");
+               return -1;
+       }
+
+       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest);
+       if (ret < 0  || ret >= MAXPATHLEN)
+               return -1;
+       if ((pid = fork()) < 0)
+               return -1;
+       if (pid)
+               return wait_for_pid(pid);
+
+       char dev[MAXPATHLEN];
+       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n);
+       if (ret < 0  || ret >= MAXPATHLEN)
+               exit(EXIT_FAILURE);
+
+       execlp("zfs", "zfs", "create", option, dev, (char *)NULL);
+       exit(EXIT_FAILURE);
+}
diff --git a/src/lxc/bdev/lxczfs.h b/src/lxc/bdev/lxczfs.h
new file mode 100644 (file)
index 0000000..0484619
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_ZFS_H
+#define __LXC_ZFS_H
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with an zfs bdev struct.
+ */
+int zfs_clone(const char *opath, const char *npath, const char *oname,
+               const char *nname, const char *lxcpath, int snapshot);
+int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
+               const char *cname, const char *oldpath, const char *lxcpath,
+               int snap, uint64_t newsize, struct lxc_conf *conf);
+int zfs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+/*
+ * TODO: detect whether this was a clone, and if so then also delete the
+ * snapshot it was based on, so that we don't hold the original
+ * container busy.
+ */
+int zfs_destroy(struct bdev *orig);
+int zfs_detect(const char *path);
+int zfs_list_entry(const char *path, char *output, size_t inlen);
+int zfs_mount(struct bdev *bdev);
+int zfs_umount(struct bdev *bdev);
+
+#endif /* __LXC_ZFS_H */
index d65f2d7..c493d58 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -43,7 +44,7 @@
 #include "list.h"
 #include "conf.h"
 #include "utils.h"
-#include "bdev.h"
+#include "bdev/bdev.h"
 #include "log.h"
 #include "cgroup.h"
 #include "start.h"
@@ -131,7 +132,8 @@ static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp);
 static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h);
 static bool is_valid_cgroup(const char *name);
 static int create_cgroup(struct cgroup_mount_point *mp, const char *path);
-static int remove_cgroup(struct cgroup_mount_point *mp, const char *path, bool recurse);
+static int remove_cgroup(struct cgroup_mount_point *mp, const char *path, bool recurse,
+                               struct lxc_conf *conf);
 static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *path, const char *suffix);
 static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
 static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
@@ -139,7 +141,6 @@ static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, cons
 static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d, char *v, bool for_allow);
 static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices);
 static int cgroup_recursive_task_count(const char *cgroup_path);
-static int count_lines(const char *fn);
 static int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path);
 static bool init_cpuset_if_needed(struct cgroup_mount_point *mp, const char *path);
 
@@ -149,7 +150,8 @@ static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *met
 
 /* free process membership information */
 static void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
-static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info);
+static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info,
+                               struct lxc_conf *conf);
 
 static struct cgroup_ops cgfs_ops;
 
@@ -222,6 +224,20 @@ static int cgroup_rmdir(char *dirname)
        return failed ? -1 : 0;
 }
 
+static int rmdir_wrapper(void *data)
+{
+       char *path = data;
+
+       if (setresgid(0,0,0) < 0)
+               SYSERROR("Failed to setgid to 0");
+       if (setresuid(0,0,0) < 0)
+               SYSERROR("Failed to setuid to 0");
+       if (setgroups(0, NULL) < 0)
+               SYSERROR("Failed to clear groups");
+
+       return cgroup_rmdir(path);
+}
+
 static struct cgroup_meta_data *lxc_cgroup_load_meta()
 {
        const char *cgroup_use = NULL;
@@ -417,6 +433,7 @@ static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **
        size_t mount_point_capacity = 0;
        size_t token_capacity = 0;
        int r;
+       bool is_cgns = cgns_supported();
 
        proc_self_mountinfo = fopen_cloexec("/proc/self/mountinfo", "r");
        /* if for some reason (because of setns() and pid namespace for example),
@@ -432,6 +449,7 @@ static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **
                struct cgroup_mount_point *mount_point;
                struct cgroup_hierarchy *h;
                char **subsystems;
+               bool is_lxcfs = false;
 
                if (line[0] && line[strlen(line) - 1] == '\n')
                        line[strlen(line) - 1] = '\0';
@@ -470,10 +488,18 @@ static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **
                        continue;
 
                /* not a cgroup filesystem */
-               if (strcmp(tokens[j + 1], "cgroup") != 0)
-                       continue;
-
-               subsystems = subsystems_from_mount_options(tokens[j + 3], kernel_subsystems);
+               if (strcmp(tokens[j + 1], "cgroup") != 0) {
+                       if (strcmp(tokens[j + 1], "fuse.lxcfs") != 0)
+                               continue;
+                       if (strncmp(tokens[4], "/sys/fs/cgroup/", 15) != 0)
+                               continue;
+                       is_lxcfs = true;
+                       char *curtok = tokens[4] + 15;
+                       subsystems = subsystems_from_mount_options(curtok,
+                                                        kernel_subsystems);
+               } else
+                       subsystems = subsystems_from_mount_options(tokens[j + 3],
+                                                        kernel_subsystems);
                if (!subsystems)
                        goto out;
 
@@ -502,8 +528,11 @@ static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **
                meta_data->mount_points[mount_point_count++] = mount_point;
 
                mount_point->hierarchy = h;
+               if (is_lxcfs || is_cgns)
+                       mount_point->mount_prefix = strdup("/");
+               else
+                       mount_point->mount_prefix = strdup(tokens[3]);
                mount_point->mount_point = strdup(tokens[4]);
-               mount_point->mount_prefix = strdup(tokens[3]);
                if (!mount_point->mount_point || !mount_point->mount_prefix)
                        goto out;
                mount_point->read_only = !lxc_string_in_list("rw", tokens[5], ',');
@@ -555,7 +584,7 @@ static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whi
                true;
        all_named_subsystems = subsystem_whitelist ?
                (lxc_string_in_array("@named", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
-               false;
+               true;
 
        meta_data = calloc(1, sizeof(struct cgroup_meta_data));
        if (!meta_data)
@@ -623,6 +652,11 @@ static struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_dat
        return NULL;
 }
 
+static bool mountpoint_is_accessible(struct cgroup_mount_point *mp)
+{
+       return mp && access(mp->mount_point, F_OK) == 0;
+}
+
 static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
 {
        struct cgroup_mount_point **mps;
@@ -630,9 +664,9 @@ static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hier
        ssize_t quality = -1;
 
        /* trivial case */
-       if (hierarchy->rw_absolute_mount_point)
+       if (mountpoint_is_accessible(hierarchy->rw_absolute_mount_point))
                return hierarchy->rw_absolute_mount_point;
-       if (!should_be_writable && hierarchy->ro_absolute_mount_point)
+       if (!should_be_writable && mountpoint_is_accessible(hierarchy->ro_absolute_mount_point))
                return hierarchy->ro_absolute_mount_point;
 
        for (mps = hierarchy->all_mount_points; mps && *mps; mps++) {
@@ -642,6 +676,9 @@ static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hier
                if (prefix_len == 1 && mp->mount_prefix[0] == '/')
                        prefix_len = 0;
 
+               if (!mountpoint_is_accessible(mp))
+                       continue;
+
                if (should_be_writable && mp->read_only)
                        continue;
 
@@ -786,6 +823,17 @@ static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, p
        return newname;
 }
 
+static bool is_crucial_hierarchy(struct cgroup_hierarchy *h)
+{
+       char **p;
+
+       for (p = h->subsystems; *p; p++) {
+               if (is_crucial_cgroup_subsystem(*p))
+                       return true;
+       }
+       return false;
+}
+
 /* create a new cgroup */
 static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
 {
@@ -886,7 +934,9 @@ static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const c
                 * In that case, remove the cgroup from all previous hierarchies
                 */
                for (j = 0, info_ptr = base_info; j < i && info_ptr; info_ptr = info_ptr->next, j++) {
-                       r = remove_cgroup(info_ptr->designated_mount_point, info_ptr->created_paths[info_ptr->created_paths_count - 1], false);
+                       if (info_ptr->created_paths_count < 1)
+                               continue;
+                       r = remove_cgroup(info_ptr->designated_mount_point, info_ptr->created_paths[info_ptr->created_paths_count - 1], false, NULL);
                        if (r < 0)
                                WARN("could not clean up cgroup we created when trying to create container");
                        free(info_ptr->created_paths[info_ptr->created_paths_count - 1]);
@@ -953,8 +1003,11 @@ static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const c
                                current_entire_path = NULL;
                                goto cleanup_name_on_this_level;
                        } else if (r < 0 && errno != EEXIST) {
-                               SYSERROR("Could not create cgroup '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
-                               goto cleanup_from_error;
+                               if (is_crucial_hierarchy(info_ptr->hierarchy)) {
+                                       SYSERROR("Could not create cgroup '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
+                                       goto cleanup_from_error;
+                               }
+                               goto skip;
                        } else if (r == 0) {
                                /* successfully created */
                                r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
@@ -978,6 +1031,7 @@ static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const c
                                        goto cleanup_from_error;
                                }
 
+skip:
                                /* already existed but path component of pattern didn't contain '%n',
                                 * so this is not an error; but then we don't need current_entire_path
                                 * anymore...
@@ -1040,7 +1094,7 @@ static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const c
 out_initial_error:
        saved_errno = errno;
        free(path_so_far);
-       lxc_cgroup_process_info_free_and_remove(base_info);
+       lxc_cgroup_process_info_free_and_remove(base_info, NULL);
        lxc_free_array((void **)new_cgroup_paths, free);
        lxc_free_array((void **)new_cgroup_paths_sub, free);
        lxc_free_array((void **)cgroup_path_components, free);
@@ -1097,7 +1151,6 @@ static struct cgroup_process_info *lxc_cgroup_get_container_info(const char *nam
                path = lxc_cmd_get_cgroup_path(name, lxcpath, h->subsystems[0]);
                if (!path) {
                        h->used = false;
-                       WARN("Not attaching to cgroup %s unknown to %s %s", h->subsystems[0], lxcpath, name);
                        continue;
                }
 
@@ -1159,7 +1212,7 @@ static int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool
 
                r = lxc_write_to_file(cgroup_tasks_fn, pid_buf, strlen(pid_buf), false);
                free(cgroup_tasks_fn);
-               if (r < 0) {
+               if (r < 0 && is_crucial_hierarchy(info_ptr->hierarchy)) {
                        SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
                        return -1;
                }
@@ -1184,7 +1237,7 @@ void lxc_cgroup_process_info_free(struct cgroup_process_info *info)
 }
 
 /* free process membership information and remove cgroups that were created */
-void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
+void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info, struct lxc_conf *conf)
 {
        struct cgroup_process_info *next;
        char **pp;
@@ -1200,7 +1253,7 @@ void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
                         * '/lxc' cgroup in this container but another container
                         * is still running (for example)
                         */
-                       (void)remove_cgroup(mp, info->cgroup_path, true);
+                       (void)remove_cgroup(mp, info->cgroup_path, true, conf);
        }
        for (pp = info->created_paths; pp && *pp; pp++);
        for ((void)(pp && --pp); info->created_paths && pp >= info->created_paths; --pp) {
@@ -1211,7 +1264,7 @@ void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
        free(info->cgroup_path);
        free(info->cgroup_path_sub);
        free(info);
-       lxc_cgroup_process_info_free_and_remove(next);
+       lxc_cgroup_process_info_free_and_remove(next, conf);
 }
 
 static char *lxc_cgroup_get_hierarchy_path_data(const char *subsystem, struct cgfs_data *d)
@@ -1284,10 +1337,13 @@ static int lxc_cgroup_set_data(const char *filename, const char *value, struct c
        if ((p = strchr(subsystem, '.')) != NULL)
                *p = '\0';
 
+       errno = ENOENT;
        path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d);
        if (path) {
                ret = do_cgroup_set(path, filename, value);
+               int saved_errno = errno;
                free(path);
+               errno = saved_errno;
        }
        return ret;
 }
@@ -1340,6 +1396,9 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
        struct cgroup_process_info *info, *base_info;
        int r, saved_errno = 0;
 
+       if (cgns_supported())
+               return true;
+
        cgfs_d = hdata;
        if (!cgfs_d)
                return false;
@@ -1377,8 +1436,9 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
        for (info = base_info; info; info = info->next) {
                size_t subsystem_count, i;
                struct cgroup_mount_point *mp = info->designated_mount_point;
-               if (!mp)
+               if (!mountpoint_is_accessible(mp))
                        mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
+
                if (!mp) {
                        SYSERROR("could not find original mount point for cgroup hierarchy while trying to mount cgroup filesystem");
                        goto out_error;
@@ -1481,7 +1541,7 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
                        if (!abs_path)
                                goto out_error;
                        r = mount(abs_path, abs_path2, "none", MS_BIND, 0);
-                       if (r < 0) {
+                       if (r < 0 && is_crucial_hierarchy(info->hierarchy)) {
                                SYSERROR("error bind-mounting %s to %s", abs_path, abs_path2);
                                goto out_error;
                        }
@@ -1661,6 +1721,7 @@ lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str,
                entry->cgroup_path = strdup(colon2);
                if (!entry->cgroup_path)
                        goto out_error;
+               prune_init_scope(entry->cgroup_path);
 
                *cptr = entry;
                cptr = &entry->next;
@@ -1699,16 +1760,20 @@ static char **subsystems_from_mount_options(const char *mount_options,
                 * subsystems provided by the kernel OR if it starts
                 * with name= for named hierarchies
                 */
-               if (!strncmp(token, "name=", 5) || lxc_string_in_array(token, (const char **)kernel_list)) {
-                       r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 12);
-                       if (r < 0)
-                               goto out_free;
-                       result[result_count + 1] = NULL;
+               r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 12);
+               if (r < 0)
+                       goto out_free;
+               result[result_count + 1] = NULL;
+               if (strncmp(token, "name=", 5) && !lxc_string_in_array(token, (const char **)kernel_list)) {
+                       // this is eg 'systemd' but the mount will be 'name=systemd'
+                       result[result_count] = malloc(strlen(token) + 6);
+                       if (result[result_count])
+                               sprintf(result[result_count], "name=%s", token);
+               } else
                        result[result_count] = strdup(token);
-                       if (!result[result_count])
-                               goto out_free;
-                       result_count++;
-               }
+               if (!result[result_count])
+                       goto out_free;
+               result_count++;
        }
 
        return result;
@@ -1753,7 +1818,8 @@ static bool is_valid_cgroup(const char *name)
 }
 
 static int create_or_remove_cgroup(bool do_remove,
-               struct cgroup_mount_point *mp, const char *path, int recurse)
+               struct cgroup_mount_point *mp, const char *path, int recurse,
+               struct lxc_conf *conf)
 {
        int r, saved_errno = 0;
        char *buf = cgroup_to_absolute_path(mp, path, NULL);
@@ -1762,9 +1828,14 @@ static int create_or_remove_cgroup(bool do_remove,
 
        /* create or remove directory */
        if (do_remove) {
-               if (recurse)
-                       r = cgroup_rmdir(buf);
-               else
+               if (!dir_exists(buf))
+                       return 0;
+               if (recurse) {
+                       if (conf && !lxc_list_empty(&conf->id_map))
+                               r = userns_exec_1(conf, rmdir_wrapper, buf);
+                       else
+                               r = cgroup_rmdir(buf);
+               } else
                        r = rmdir(buf);
        } else
                r = mkdir(buf, 0777);
@@ -1776,13 +1847,13 @@ static int create_or_remove_cgroup(bool do_remove,
 
 static int create_cgroup(struct cgroup_mount_point *mp, const char *path)
 {
-       return create_or_remove_cgroup(false, mp, path, false);
+       return create_or_remove_cgroup(false, mp, path, false, NULL);
 }
 
 static int remove_cgroup(struct cgroup_mount_point *mp,
-                        const char *path, bool recurse)
+                        const char *path, bool recurse, struct lxc_conf *conf)
 {
-       return create_or_remove_cgroup(true, mp, path, recurse);
+       return create_or_remove_cgroup(true, mp, path, recurse, conf);
 }
 
 static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp,
@@ -1913,7 +1984,12 @@ static int do_setup_cgroup_limits(struct cgfs_data *d,
                                        cgroup_devices_has_allow_or_deny(d, cg->value, true))
                                continue;
                        if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
-                               ERROR("Error setting %s to %s for %s",
+                               if (do_devices && (errno == EACCES || errno == EPERM)) {
+                                       WARN("Error setting %s to %s for %s",
+                                             cg->subsystem, cg->value, d->name);
+                                       continue;
+                               }
+                               SYSERROR("Error setting %s to %s for %s",
                                      cg->subsystem, cg->value, d->name);
                                goto out;
                        }
@@ -2039,7 +2115,7 @@ static int cgroup_recursive_task_count(const char *cgroup_path)
                        if (r >= 0)
                                n += r;
                } else if (!strcmp(dent->d_name, "tasks")) {
-                       r = count_lines(sub_path);
+                       r = lxc_count_file_lines(sub_path);
                        if (r >= 0)
                                n += r;
                }
@@ -2051,25 +2127,6 @@ static int cgroup_recursive_task_count(const char *cgroup_path)
        return n;
 }
 
-static int count_lines(const char *fn)
-{
-       FILE *f;
-       char *line = NULL;
-       size_t sz = 0;
-       int n = 0;
-
-       f = fopen_cloexec(fn, "r");
-       if (!f)
-               return -1;
-
-       while (getline(&line, &sz, f) != -1) {
-               n++;
-       }
-       free(line);
-       fclose(f);
-       return n;
-}
-
 static int handle_cgroup_settings(struct cgroup_mount_point *mp,
                                  char *cgroup_path)
 {
@@ -2255,14 +2312,14 @@ err1:
        return NULL;
 }
 
-static void cgfs_destroy(void *hdata)
+static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
 {
        struct cgfs_data *d = hdata;
 
        if (!d)
                return;
        free(d->name);
-       lxc_cgroup_process_info_free_and_remove(d->info);
+       lxc_cgroup_process_info_free_and_remove(d->info, conf);
        lxc_cgroup_put_meta(d->meta);
        free(d);
 }
@@ -2343,6 +2400,55 @@ static const char *cgfs_canonical_path(void *hdata)
        return path;
 }
 
+static bool cgfs_escape(void *hdata)
+{
+       struct cgroup_meta_data *md;
+       int i;
+       bool ret = false;
+
+       md = lxc_cgroup_load_meta();
+       if (!md)
+               return false;
+
+       for (i = 1; i <= md->maximum_hierarchy; i++) {
+               struct cgroup_hierarchy *h = md->hierarchies[i];
+               struct cgroup_mount_point *mp;
+               char *tasks;
+               FILE *f;
+               int written;
+
+               if (!h) {
+                       WARN("not escaping hierarchy %d", i);
+                       continue;
+               }
+
+               mp = lxc_cgroup_find_mount_point(h, "/", true);
+               if (!mp)
+                       goto out;
+
+               tasks = cgroup_to_absolute_path(mp, "/", "tasks");
+               if (!tasks)
+                       goto out;
+
+               f = fopen(tasks, "a");
+               free(tasks);
+               if (!f)
+                       goto out;
+
+               written = fprintf(f, "%d\n", getpid());
+               fclose(f);
+               if (written < 0) {
+                       SYSERROR("writing tasks failed\n");
+                       goto out;
+               }
+       }
+
+       ret = true;
+out:
+       lxc_cgroup_put_meta(md);
+       return ret;
+}
+
 static bool cgfs_unfreeze(void *hdata)
 {
        struct cgfs_data *d = hdata;
@@ -2400,6 +2506,133 @@ static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid
        return true;
 }
 
+struct chown_data {
+       const char *cgroup_path;
+       uid_t origuid;
+};
+
+/*
+ * TODO - someone should refactor this to unshare once passing all the paths
+ * to be chowned in one go
+ */
+static int chown_cgroup_wrapper(void *data)
+{
+       struct chown_data *arg = data;
+       uid_t destuid;
+       char *fpath;
+
+       if (setresgid(0,0,0) < 0)
+               SYSERROR("Failed to setgid to 0");
+       if (setresuid(0,0,0) < 0)
+               SYSERROR("Failed to setuid to 0");
+       if (setgroups(0, NULL) < 0)
+               SYSERROR("Failed to clear groups");
+       destuid = get_ns_uid(arg->origuid);
+
+       if (chown(arg->cgroup_path, destuid, 0) < 0)
+               SYSERROR("Failed chowning %s to %d", arg->cgroup_path, (int)destuid);
+
+       fpath = lxc_append_paths(arg->cgroup_path, "tasks");
+       if (!fpath)
+               return -1;
+       if (chown(fpath, destuid, 0) < 0)
+               SYSERROR("Error chowning %s\n", fpath);
+       free(fpath);
+
+       fpath = lxc_append_paths(arg->cgroup_path, "cgroup.procs");
+       if (!fpath)
+               return -1;
+       if (chown(fpath, destuid, 0) < 0)
+               SYSERROR("Error chowning %s", fpath);
+       free(fpath);
+
+       return 0;
+}
+
+static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
+{
+       struct chown_data data;
+       char *fpath;
+
+       if (!dir_exists(cgroup_path))
+               return true;
+
+       if (lxc_list_empty(&conf->id_map))
+               /* If there's no mapping then we don't need to chown */
+               return true;
+
+       data.cgroup_path = cgroup_path;
+       data.origuid = geteuid();
+
+       /* Unpriv users can't chown it themselves, so chown from
+        * a child namespace mapping both our own and the target uid
+        */
+       if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
+               ERROR("Error requesting cgroup chown in new namespace");
+               return false;
+       }
+
+       /*
+        * Now chmod 775 the directory else the container cannot create cgroups.
+        * This can't be done in the child namespace because it only group-owns
+        * the cgroup
+        */
+       if (chmod(cgroup_path, 0775) < 0) {
+               SYSERROR("Error chmoding %s\n", cgroup_path);
+               return false;
+       }
+       fpath = lxc_append_paths(cgroup_path, "tasks");
+       if (!fpath)
+               return false;
+       if (chmod(fpath, 0664) < 0)
+               SYSERROR("Error chmoding %s\n", fpath);
+       free(fpath);
+       fpath = lxc_append_paths(cgroup_path, "cgroup.procs");
+       if (!fpath)
+               return false;
+       if (chmod(fpath, 0664) < 0)
+               SYSERROR("Error chmoding %s\n", fpath);
+       free(fpath);
+
+       return true;
+}
+
+static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
+{
+       struct cgfs_data *d = hdata;
+       struct cgroup_process_info *info_ptr;
+       char *cgpath;
+       bool r = true;
+
+       if (!d)
+               return false;
+
+       for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
+               if (!info_ptr->designated_mount_point) {
+                       info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, info_ptr->cgroup_path, true);
+                       if (!info_ptr->designated_mount_point) {
+                               SYSERROR("Could not chown cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", info_ptr->cgroup_path);
+                               return false;
+                       }
+               }
+
+               cgpath = cgroup_to_absolute_path(info_ptr->designated_mount_point, info_ptr->cgroup_path, NULL);
+               if (!cgpath) {
+                       SYSERROR("Could not chown cgroup %s: internal error", info_ptr->cgroup_path);
+                       continue;
+               }
+               r = do_cgfs_chown(cgpath, conf);
+               if (!r && is_crucial_hierarchy(info_ptr->hierarchy)) {
+                       ERROR("Failed chowning %s\n", cgpath);
+                       free(cgpath);
+                       return false;
+               }
+               free(cgpath);
+       }
+
+       return true;
+}
+
 static struct cgroup_ops cgfs_ops = {
        .init = cgfs_init,
        .destroy = cgfs_destroy,
@@ -2408,13 +2641,14 @@ static struct cgroup_ops cgfs_ops = {
        .create_legacy = cgfs_create_legacy,
        .get_cgroup = cgfs_get_cgroup,
        .canonical_path = cgfs_canonical_path,
+       .escape = cgfs_escape,
        .get = lxc_cgroupfs_get,
        .set = lxc_cgroupfs_set,
        .unfreeze = cgfs_unfreeze,
        .setup_limits = cgroupfs_setup_limits,
        .name = "cgroupfs",
        .attach = lxc_cgroupfs_attach,
-       .chown = NULL,
+       .chown = cgfs_chown,
        .mount_cgroup = cgroupfs_mount_cgroup,
        .nrtasks = cgfs_nrtasks,
        .driver = CGFS,
diff --git a/src/lxc/cgfsng.c b/src/lxc/cgfsng.c
new file mode 100644 (file)
index 0000000..cf75319
--- /dev/null
@@ -0,0 +1,1748 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * cgfs-ng.c: this is a new, simplified implementation of a filesystem
+ * cgroup backend.  The original cgfs.c was designed to be as flexible
+ * as possible.  It would try to find cgroup filesystems no matter where
+ * or how you had them mounted, and deduce the most usable mount for
+ * each controller.  It also was not designed for unprivileged use, as
+ * that was reserved for cgmanager.
+ *
+ * This new implementation assumes that cgroup filesystems are mounted
+ * under /sys/fs/cgroup/clist where clist is either the controller, or
+ * a comman-separated list of controllers.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <grp.h>
+
+#include "log.h"
+#include "cgroup.h"
+#include "utils.h"
+#include "commands.h"
+#include "bdev/bdev.h"
+
+lxc_log_define(lxc_cgfsng, lxc);
+
+static struct cgroup_ops cgfsng_ops;
+
+/*
+ * A descriptor for a mounted hierarchy
+ * @controllers: either NULL, or a null-terminated list of all
+ *   the co-mounted controllers
+ * @mountpoint: the mountpoint we will use.  It will be either
+ *   /sys/fs/cgroup/controller or /sys/fs/cgroup/controllerlist
+ * @base_cgroup: the cgroup under which the container cgroup path
+     is created.  This will be either the caller's cgroup (if not
+     root), or init's cgroup (if root).
+ */
+struct hierarchy {
+       char **controllers;
+       char *mountpoint;
+       char *base_cgroup;
+       char *fullcgpath;
+};
+
+/*
+ * The cgroup data which is attached to the lxc_handler.
+ * @hierarchies - a NULL-terminated array of struct hierarchy, one per
+ *   hierarchy.  No duplicates.  First sufficient, writeable mounted
+ *   hierarchy wins
+ * @cgroup_use - a copy of the lxc.cgroup.use
+ * @cgroup_pattern - a copy of the lxc.cgroup.pattern
+ * @container_cgroup - if not null, the cgroup which was created for
+ *   the container.  For each hierarchy, it is created under the
+ *   @hierarchy->base_cgroup directory.  Relative to the base_cgroup
+ *   it is the same for all hierarchies.
+ * @name - the container name
+ */
+struct cgfsng_handler_data {
+       struct hierarchy **hierarchies;
+       char *cgroup_use;
+       char *cgroup_pattern;
+       char *container_cgroup; // cgroup we created for the container
+       char *name; // container name
+};
+
+static void free_string_list(char **clist)
+{
+       if (clist) {
+               int i;
+
+               for (i = 0; clist[i]; i++)
+                       free(clist[i]);
+               free(clist);
+       }
+}
+
+/* Re-alllocate a pointer, do not fail */
+static void *must_realloc(void *orig, size_t sz)
+{
+       void *ret;
+
+       do {
+               ret = realloc(orig, sz);
+       } while (!ret);
+       return ret;
+}
+
+/* Allocate a pointer, do not fail */
+static void *must_alloc(size_t sz)
+{
+       return must_realloc(NULL, sz);
+}
+
+/* return copy of string @entry;  do not fail. */
+static char *must_copy_string(const char *entry)
+{
+       char *ret;
+
+       if (!entry)
+               return NULL;
+       do {
+               ret = strdup(entry);
+       } while (!ret);
+       return ret;
+}
+
+/*
+ * This is a special case - return a copy of @entry
+ * prepending 'name='.  I.e. turn systemd into name=systemd.
+ * Do not fail.
+ */
+static char *must_prefix_named(char *entry)
+{
+       char *ret;
+       size_t len = strlen(entry);
+
+       ret = must_alloc(len + 6);
+       snprintf(ret, len + 6, "name=%s", entry);
+       return ret;
+}
+
+/*
+ * Given a pointer to a null-terminated array of pointers, realloc to
+ * add one entry, and point the new entry to NULL.  Do not fail.  Return
+ * the index to the second-to-last entry - that is, the one which is
+ * now available for use (keeping the list null-terminated).
+ */
+static int append_null_to_list(void ***list)
+{
+       int newentry = 0;
+
+       if (*list)
+               for (; (*list)[newentry]; newentry++);
+
+       *list = must_realloc(*list, (newentry + 2) * sizeof(void **));
+       (*list)[newentry + 1] = NULL;
+       return newentry;
+}
+
+/*
+ * Given a null-terminated array of strings, check whether @entry
+ * is one of the strings
+ */
+static bool string_in_list(char **list, const char *entry)
+{
+       int i;
+
+       if (!list)
+               return false;
+       for (i = 0; list[i]; i++)
+               if (strcmp(list[i], entry) == 0)
+                       return true;
+
+       return false;
+}
+
+/*
+ * append an entry to the clist.  Do not fail.
+ * *clist must be NULL the first time we are called.
+ *
+ * We also handle named subsystems here.  Any controller which is not a
+ * kernel subsystem, we prefix 'name='.  Any which is both a kernel and
+ * named subsystem, we refuse to use because we're not sure which we
+ * have here.  (TODO - we could work around this in some cases by just
+ * remounting to be unambiguous, or by comparing mountpoint contents
+ * with current cgroup)
+ *
+ * The last entry will always be NULL.
+ */
+static void must_append_controller(char **klist, char **nlist, char ***clist, char *entry)
+{
+       int newentry;
+       char *copy;
+
+       if (string_in_list(klist, entry) && string_in_list(nlist, entry)) {
+               ERROR("Refusing to use ambiguous controller '%s'", entry);
+               ERROR("It is both a named and kernel subsystem");
+               return;
+       }
+
+       newentry = append_null_to_list((void ***)clist);
+
+       if (strncmp(entry, "name=", 5) == 0)
+               copy = must_copy_string(entry);
+       else if (string_in_list(klist, entry))
+               copy = must_copy_string(entry);
+       else
+               copy = must_prefix_named(entry);
+
+       (*clist)[newentry] = copy;
+}
+
+static void free_hierarchies(struct hierarchy **hlist)
+{
+       if (hlist) {
+               int i;
+
+               for (i = 0; hlist[i]; i++) {
+                       free(hlist[i]->mountpoint);
+                       free(hlist[i]->base_cgroup);
+                       free(hlist[i]->fullcgpath);
+                       free_string_list(hlist[i]->controllers);
+               }
+               free(hlist);
+       }
+}
+
+static void free_handler_data(struct cgfsng_handler_data *d)
+{
+       free_hierarchies(d->hierarchies);
+       free(d->cgroup_use);
+       free(d->cgroup_pattern);
+       free(d->container_cgroup);
+       free(d->name);
+       free(d);
+}
+
+/*
+ * Given a handler's cgroup data, return the struct hierarchy for the
+ * controller @c, or NULL if there is none.
+ */
+struct hierarchy *get_hierarchy(struct cgfsng_handler_data *d, const char *c)
+{
+       int i;
+
+       if (!d || !d->hierarchies)
+               return NULL;
+       for (i = 0; d->hierarchies[i]; i++) {
+               if (string_in_list(d->hierarchies[i]->controllers, c))
+                       return d->hierarchies[i];
+       }
+       return NULL;
+}
+
+static char *must_make_path(const char *first, ...) __attribute__((sentinel));
+
+/* Copy contents of parent(@path)/@file to @path/@file */
+static bool copy_parent_file(char *path, char *file)
+{
+       char *lastslash, *value = NULL, *fpath, oldv;
+       int len = 0;
+       int ret;
+
+       lastslash = strrchr(path, '/');
+       if (!lastslash) { // bug...  this shouldn't be possible
+               ERROR("cgfsng:copy_parent_file: bad path %s", path);
+               return false;
+       }
+       oldv = *lastslash;
+       *lastslash = '\0';
+       fpath = must_make_path(path, file, NULL);
+       len = lxc_read_from_file(fpath, NULL, 0);
+       if (len <= 0)
+               goto bad;
+       value = must_alloc(len + 1);
+       if (lxc_read_from_file(fpath, value, len) != len)
+               goto bad;
+       free(fpath);
+       *lastslash = oldv;
+       fpath = must_make_path(path, file, NULL);
+       ret = lxc_write_to_file(fpath, value, len, false);
+       if (ret < 0)
+               SYSERROR("Unable to write %s to %s", value, fpath);
+       free(fpath);
+       free(value);
+       return ret >= 0;
+
+bad:
+       SYSERROR("Error reading '%s'", fpath);
+       free(fpath);
+       free(value);
+       return false;
+}
+
+/*
+ * Initialize the cpuset hierarchy in first directory of @gname and
+ * set cgroup.clone_children so that children inherit settings.
+ * Since the h->base_path is populated by init or ourselves, we know
+ * it is already initialized.
+ */
+bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
+{
+       char *cgpath, *clonechildrenpath, v, *slash;
+
+       if (!string_in_list(h->controllers, "cpuset"))
+               return true;
+
+       if (*cgname == '/')
+               cgname++;
+       slash = strchr(cgname, '/');
+       if (slash)
+               *slash = '\0';
+
+       cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+       if (slash)
+               *slash = '/';
+       if (mkdir(cgpath, 0755) < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create '%s'", cgpath);
+               free(cgpath);
+               return false;
+       }
+       clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
+       if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
+               free(clonechildrenpath);
+               free(cgpath);
+               return true;
+       }
+       if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
+               SYSERROR("Failed to read '%s'", clonechildrenpath);
+               free(clonechildrenpath);
+               free(cgpath);
+               return false;
+       }
+
+       if (v == '1') {  /* already set for us by someone else */
+               free(clonechildrenpath);
+               free(cgpath);
+               return true;
+       }
+
+       /* copy parent's settings */
+       if (!copy_parent_file(cgpath, "cpuset.cpus") ||
+                       !copy_parent_file(cgpath, "cpuset.mems")) {
+               free(cgpath);
+               free(clonechildrenpath);
+               return false;
+       }
+       free(cgpath);
+
+       if (lxc_write_to_file(clonechildrenpath, "1", 1, false) < 0) {
+               /* Set clone_children so children inherit our settings */
+               SYSERROR("Failed to write 1 to %s", clonechildrenpath);
+               free(clonechildrenpath);
+               return false;
+       }
+       free(clonechildrenpath);
+       return true;
+}
+
+/*
+ * Given two null-terminated lists of strings, return true if any string
+ * is in both.
+ */
+static bool controller_lists_intersect(char **l1, char **l2)
+{
+       int i;
+
+       if (!l1 || !l2)
+               return false;
+
+       for (i = 0; l1[i]; i++) {
+               if (string_in_list(l2, l1[i]))
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * For a null-terminated list of controllers @clist, return true if any of
+ * those controllers is already listed the null-terminated list of
+ * hierarchies @hlist.  Realistically, if one is present, all must be present.
+ */
+static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
+{
+       int i;
+
+       if (!hlist)
+               return false;
+       for (i = 0; hlist[i]; i++)
+               if (controller_lists_intersect(hlist[i]->controllers, clist))
+                       return true;
+       return false;
+
+}
+
+/*
+ * Return true if the controller @entry is found in the null-terminated
+ * list of hierarchies @hlist
+ */
+static bool controller_found(struct hierarchy **hlist, char *entry)
+{
+       int i;
+       if (!hlist)
+               return false;
+
+       for (i = 0; hlist[i]; i++)
+               if (string_in_list(hlist[i]->controllers, entry))
+                       return true;
+       return false;
+}
+
+/*
+ * Return true if all of the controllers which we require have been
+ * found.  The required list is systemd, freezer, and anything in
+ * lxc.cgroup.use.
+ */
+static bool all_controllers_found(struct cgfsng_handler_data *d)
+{
+       char *p, *saveptr = NULL;
+       struct hierarchy ** hlist = d->hierarchies;
+
+       if (!controller_found(hlist, "name=systemd")) {
+               ERROR("no systemd controller mountpoint found");
+               return false;
+       }
+       if (!controller_found(hlist, "freezer")) {
+               ERROR("no freezer controller mountpoint found");
+               return false;
+       }
+
+       if (!d->cgroup_use)
+               return true;
+       for (p = strtok_r(d->cgroup_use, ",", &saveptr); p;
+                       p = strtok_r(NULL, ",", &saveptr)) {
+               if (!controller_found(hlist, p)) {
+                       ERROR("no %s controller mountpoint found", p);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/* Return true if the fs type is fuse.lxcfs */
+static bool is_lxcfs(const char *line)
+{
+       char *p = strstr(line, " - ");
+       if (!p)
+               return false;
+       return strncmp(p, " - fuse.lxcfs ", 14);
+}
+
+/*
+ * Get the controllers from a mountinfo line
+ * There are other ways we could get this info.  For lxcfs, field 3
+ * is /cgroup/controller-list.  For cgroupfs, we could parse the mount
+ * options.  But we simply assume that the mountpoint must be
+ * /sys/fs/cgroup/controller-list
+ */
+static char **get_controllers(char **klist, char **nlist, char *line)
+{
+       // the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
+       int i;
+       char *p = line, *p2, *tok, *saveptr = NULL;
+       char **aret = NULL;
+
+       for (i = 0; i < 4; i++) {
+               p = strchr(p, ' ');
+               if (!p)
+                       return NULL;
+               p++;
+       }
+       if (!p)
+               return NULL;
+       /* note - if we change how mountinfo works, then our caller
+        * will need to verify /sys/fs/cgroup/ in this field */
+       if (strncmp(p, "/sys/fs/cgroup/", 15) != 0)
+               return NULL;
+       p += 15;
+       p2 = strchr(p, ' ');
+       if (!p2) {
+               ERROR("corrupt mountinfo");
+               return NULL;
+       }
+       *p2 = '\0';
+       for (tok = strtok_r(p, ",", &saveptr); tok;
+                       tok = strtok_r(NULL, ",", &saveptr)) {
+               must_append_controller(klist, nlist, &aret, tok);
+       }
+
+       return aret;
+}
+
+/* return true if the fstype is cgroup */
+static bool is_cgroupfs(char *line)
+{
+       char *p = strstr(line, " - ");
+       if (!p)
+               return false;
+       return strncmp(p, " - cgroup ", 10);
+}
+
+/* Add a controller to our list of hierarchies */
+static void add_controller(struct cgfsng_handler_data *d, char **clist,
+                          char *mountpoint, char *base_cgroup)
+{
+       struct hierarchy *new;
+       int newentry;
+
+       new = must_alloc(sizeof(*new));
+       new->controllers = clist;
+       new->mountpoint = mountpoint;
+       new->base_cgroup = base_cgroup;
+       new->fullcgpath = NULL;
+
+       newentry = append_null_to_list((void ***)&d->hierarchies);
+       d->hierarchies[newentry] = new;
+}
+
+/*
+ * Get a copy of the mountpoint from @line, which is a line from
+ * /proc/self/mountinfo
+ */
+static char *get_mountpoint(char *line)
+{
+       int i;
+       char *p = line, *sret;
+       size_t len;
+
+       for (i = 0; i < 4; i++) {
+               p = strchr(p, ' ');
+               if (!p)
+                       return NULL;
+               p++;
+       }
+       /* we've already stuck a \0 after the mountpoint */
+       len = strlen(p);
+       sret = must_alloc(len + 1);
+       memcpy(sret, p, len);
+       sret[len] = '\0';
+       return sret;
+}
+
+/*
+ * Given a multi-line string, return a null-terminated copy of the
+ * current line.
+ */
+static char *copy_to_eol(char *p)
+{
+       char *p2 = strchr(p, '\n'), *sret;
+       size_t len;
+
+       if (!p2)
+               return NULL;
+
+       len = p2 - p;
+       sret = must_alloc(len + 1);
+       memcpy(sret, p, len);
+       sret[len] = '\0';
+       return sret;
+}
+
+/*
+ * cgline: pointer to character after the first ':' in a line in a
+ * \n-terminated /proc/self/cgroup file. Check whether * controller c is
+ * present.
+ */
+static bool controller_in_clist(char *cgline, char *c)
+{
+       char *tok, *saveptr = NULL, *eol, *tmp;
+       size_t len;
+
+       eol = strchr(cgline, ':');
+       if (!eol)
+               return false;
+
+       len = eol - cgline;
+       tmp = alloca(len + 1);
+       memcpy(tmp, cgline, len);
+       tmp[len] = '\0';
+
+       for (tok = strtok_r(tmp, ",", &saveptr); tok;
+                       tok = strtok_r(NULL, ",", &saveptr)) {
+               if (strcmp(tok, c) == 0)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * @basecginfo is a copy of /proc/$$/cgroup.  Return the current
+ * cgroup for @controller
+ */
+static char *get_current_cgroup(char *basecginfo, char *controller)
+{
+       char *p = basecginfo;
+
+       while (1) {
+               p = strchr(p, ':');
+               if (!p)
+                       return NULL;
+               p++;
+               if (controller_in_clist(p, controller)) {
+                       p = strchr(p, ':');
+                       if (!p)
+                               return NULL;
+                       p++;
+                       return copy_to_eol(p);
+               }
+
+               p = strchr(p, '\n');
+               if (!p)
+                       return NULL;
+               p++;
+       }
+}
+
+#define BATCH_SIZE 50
+static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
+{
+       int newbatches = (newlen / BATCH_SIZE) + 1;
+       int oldbatches = (oldlen / BATCH_SIZE) + 1;
+
+       if (!*mem || newbatches > oldbatches) {
+               *mem = must_realloc(*mem, newbatches * BATCH_SIZE);
+       }
+}
+
+static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
+{
+       size_t full = oldlen + newlen;
+
+       batch_realloc(dest, oldlen, full + 1);
+
+       memcpy(*dest + oldlen, new, newlen + 1);
+}
+
+/* Slurp in a whole file */
+static char *read_file(char *fnam)
+{
+       FILE *f;
+       char *line = NULL, *buf = NULL;
+       size_t len = 0, fulllen = 0;
+       int linelen;
+
+       f = fopen(fnam, "r");
+       if (!f)
+               return NULL;
+       while ((linelen = getline(&line, &len, f)) != -1) {
+               append_line(&buf, fulllen, line, linelen);
+               fulllen += linelen;
+       }
+       fclose(f);
+       free(line);
+       return buf;
+}
+
+/*
+ * Given a hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it.
+ */
+static bool test_writeable(char *mountpoint, char *path)
+{
+       char *fullpath = must_make_path(mountpoint, path, NULL);
+       int ret;
+
+       ret = access(fullpath, W_OK);
+       free(fullpath);
+       return ret == 0;
+}
+
+static void must_append_string(char ***list, char *entry)
+{
+       int newentry = append_null_to_list((void ***)list);
+       char *copy;
+
+       copy = must_copy_string(entry);
+       (*list)[newentry] = copy;
+}
+
+static void get_existing_subsystems(char ***klist, char ***nlist)
+{
+       FILE *f;
+       char *line = NULL;
+       size_t len = 0;
+
+       if ((f = fopen("/proc/self/cgroup", "r")) == NULL)
+               return;
+       while (getline(&line, &len, f) != -1) {
+               char *p, *p2, *tok, *saveptr = NULL;
+               p = strchr(line, ':');
+               if (!p)
+                       continue;
+               p++;
+               p2 = strchr(p, ':');
+               if (!p2)
+                       continue;
+               *p2 = '\0';
+               for (tok = strtok_r(p, ",", &saveptr); tok;
+                               tok = strtok_r(NULL, ",", &saveptr)) {
+                       if (strncmp(tok, "name=", 5) == 0)
+                               must_append_string(nlist, tok);
+                       else
+                               must_append_string(klist, tok);
+               }
+       }
+
+       free(line);
+       fclose(f);
+}
+
+static void trim(char *s)
+{
+       size_t len = strlen(s);
+       while (s[len-1] == '\n')
+               s[--len] = '\0';
+}
+
+static void print_init_debuginfo(struct cgfsng_handler_data *d)
+{
+       int i;
+
+       if (!getenv("LXC_DEBUG_CGFSNG"))
+               return;
+
+       printf("Cgroup information:\n");
+       printf("  container name: %s\n", d->name);
+       printf("  lxc.cgroup.use: %s\n", d->cgroup_use ? d->cgroup_use : "(none)");
+       printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern);
+       printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(none)");
+       if (!d->hierarchies) {
+               printf("  No hierarchies found.\n");
+               return;
+       }
+       printf("  Hierarchies:\n");
+       for (i = 0; d->hierarchies[i]; i++) {
+               struct hierarchy *h = d->hierarchies[i];
+               int j;
+               printf("  %d: base_cgroup %s\n", i, h->base_cgroup);
+               printf("      mountpoint %s\n", h->mountpoint);
+               printf("      controllers:\n");
+               for (j = 0; h->controllers[j]; j++)
+                       printf("     %d: %s\n", j, h->controllers[j]);
+       }
+}
+
+static void print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
+{
+       int k;
+       if (!getenv("LXC_DEBUG_CGFSNG"))
+               return;
+
+       printf("basecginfo is %s\n", basecginfo);
+
+       for (k = 0; klist[k]; k++)
+               printf("kernel subsystem %d: %s\n", k, klist[k]);
+       for (k = 0; nlist[k]; k++)
+               printf("named subsystem %d: %s\n", k, nlist[k]);
+}
+
+/*
+ * At startup, parse_hierarchies finds all the info we need about
+ * cgroup mountpoints and current cgroups, and stores it in @d.
+ */
+static bool parse_hierarchies(struct cgfsng_handler_data *d)
+{
+       FILE *f;
+       char * line = NULL, *basecginfo;
+       char **klist = NULL, **nlist = NULL;
+       size_t len = 0;
+
+       /*
+        * Root spawned containers escape the current cgroup, so use init's
+        * cgroups as our base in that case.
+        */
+       if (geteuid())
+               basecginfo = read_file("/proc/self/cgroup");
+       else
+               basecginfo = read_file("/proc/1/cgroup");
+       if (!basecginfo)
+               return false;
+
+       if ((f = fopen("/proc/self/mountinfo", "r")) == NULL) {
+               SYSERROR("Failed opening /proc/self/mountinfo");
+               return false;
+       }
+
+       get_existing_subsystems(&klist, &nlist);
+
+       print_basecg_debuginfo(basecginfo, klist, nlist);
+
+       /* we support simple cgroup mounts and lxcfs mounts */
+       while (getline(&line, &len, f) != -1) {
+               char **controller_list = NULL;
+               char *mountpoint, *base_cgroup;
+
+               if (!is_lxcfs(line) && !is_cgroupfs(line))
+                       continue;
+
+               controller_list = get_controllers(klist, nlist, line);
+               if (!controller_list)
+                       continue;
+
+               if (controller_list_is_dup(d->hierarchies, controller_list)) {
+                       free(controller_list);
+                       continue;
+               }
+
+               mountpoint = get_mountpoint(line);
+               if (!mountpoint) {
+                       ERROR("Error reading mountinfo: bad line '%s'", line);
+                       free_string_list(controller_list);
+                       continue;
+               }
+
+               base_cgroup = get_current_cgroup(basecginfo, controller_list[0]);
+               if (!base_cgroup) {
+                       ERROR("Failed to find current cgroup for controller '%s'", controller_list[0]);
+                       free_string_list(controller_list);
+                       free(mountpoint);
+                       continue;
+               }
+               trim(base_cgroup);
+               prune_init_scope(base_cgroup);
+               if (!test_writeable(mountpoint, base_cgroup)) {
+                       free_string_list(controller_list);
+                       free(mountpoint);
+                       free(base_cgroup);
+                       continue;
+               }
+               add_controller(d, controller_list, mountpoint, base_cgroup);
+       }
+
+       free_string_list(klist);
+       free_string_list(nlist);
+
+       free(basecginfo);
+
+       fclose(f);
+       free(line);
+
+       print_init_debuginfo(d);
+
+       /* verify that all controllers in cgroup.use and all crucial
+        * controllers are accounted for
+        */
+       if (!all_controllers_found(d))
+               return false;
+
+       return true;
+}
+
+static void *cgfsng_init(const char *name)
+{
+       struct cgfsng_handler_data *d;
+       const char *cgroup_use, *cgroup_pattern;
+
+       d = must_alloc(sizeof(*d));
+       memset(d, 0, sizeof(*d));
+
+       d->name = must_copy_string(name);
+
+       errno = 0;
+       cgroup_use = lxc_global_config_value("lxc.cgroup.use");
+       if (!cgroup_use && errno != 0) { // lxc.cgroup.use can be NULL
+               SYSERROR("Error reading list of cgroups to use");
+               goto out_free;
+       }
+       d->cgroup_use = must_copy_string(cgroup_use);
+
+       cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+       if (!cgroup_pattern) { // lxc.cgroup.pattern is only NULL on error
+               ERROR("Error getting cgroup pattern");
+               goto out_free;
+       }
+       d->cgroup_pattern = must_copy_string(cgroup_pattern);
+
+       if (!parse_hierarchies(d))
+               goto out_free;
+
+       print_init_debuginfo(d);
+
+       return d;
+
+out_free:
+       free_handler_data(d);
+       return NULL;
+}
+
+/*
+ * Concatenate all passed-in strings into one path.  Do not fail.  If any piece is
+ * not prefixed with '/', add a '/'.
+ */
+static char *must_make_path(const char *first, ...)
+{
+       va_list args;
+       char *cur, *dest;
+       size_t full_len = strlen(first);
+
+       dest = must_copy_string(first);
+
+       va_start(args, first);
+       while ((cur = va_arg(args, char *)) != NULL) {
+               full_len += strlen(cur);
+               if (cur[0] != '/')
+                       full_len++;
+               dest = must_realloc(dest, full_len + 1);
+               if (cur[0] != '/')
+                       strcat(dest, "/");
+               strcat(dest, cur);
+       }
+       va_end(args);
+
+       return dest;
+}
+
+static int cgroup_rmdir(char *dirname)
+{
+       struct dirent dirent, *direntp;
+       DIR *dir;
+       int r = 0;
+
+       dir = opendir(dirname);
+       if (!dir)
+               return -1;
+
+       while (!readdir_r(dir, &dirent, &direntp)) {
+               struct stat mystat;
+               char *pathname;
+
+               if (!direntp)
+                       break;
+
+               if (!strcmp(direntp->d_name, ".") ||
+                   !strcmp(direntp->d_name, ".."))
+                       continue;
+
+               pathname = must_make_path(dirname, direntp->d_name, NULL);
+
+               if (lstat(pathname, &mystat)) {
+                       if (!r)
+                               WARN("failed to stat %s", pathname);
+                       r = -1;
+                       goto next;
+               }
+
+               if (!S_ISDIR(mystat.st_mode))
+                       goto next;
+               if (cgroup_rmdir(pathname) < 0)
+                       r = -1;
+next:
+               free(pathname);
+       }
+
+       if (rmdir(dirname) < 0) {
+               if (!r)
+                       WARN("%s: failed to delete %s: %m", __func__, dirname);
+               r = -1;
+       }
+
+       if (closedir(dir) < 0) {
+               if (!r)
+                       WARN("%s: failed to delete %s: %m", __func__, dirname);
+               r = -1;
+       }
+       return r;
+}
+
+static int rmdir_wrapper(void *data)
+{
+       char *path = data;
+
+       if (setresgid(0,0,0) < 0)
+               SYSERROR("Failed to setgid to 0");
+       if (setresuid(0,0,0) < 0)
+               SYSERROR("Failed to setuid to 0");
+       if (setgroups(0, NULL) < 0)
+               SYSERROR("Failed to clear groups");
+
+       return cgroup_rmdir(path);
+}
+
+void recursive_destroy(char *path, struct lxc_conf *conf)
+{
+       int r;
+       if (conf && !lxc_list_empty(&conf->id_map))
+               r = userns_exec_1(conf, rmdir_wrapper, path);
+       else
+               r = cgroup_rmdir(path);
+
+       if (r < 0)
+               ERROR("Error destroying %s", path);
+}
+
+static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
+{
+       struct cgfsng_handler_data *d = hdata;
+
+       if (!d)
+               return;
+
+       if (d->container_cgroup && d->hierarchies) {
+               int i;
+               for (i = 0; d->hierarchies[i]; i++) {
+                       struct hierarchy *h = d->hierarchies[i];
+                       if (h->fullcgpath) {
+                               recursive_destroy(h->fullcgpath, conf);
+                               free(h->fullcgpath);
+                               h->fullcgpath = NULL;
+                       }
+               }
+       }
+
+       free_handler_data(d);
+}
+
+struct cgroup_ops *cgfsng_ops_init(void)
+{
+       return &cgfsng_ops;
+}
+
+static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
+{
+       h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+       if (dir_exists(h->fullcgpath)) // it must not already exist
+               return false;
+       if (!handle_cpuset_hierarchy(h, cgname))
+               return false;
+       return mkdir_p(h->fullcgpath, 0755) == 0;
+}
+
+static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
+{
+       if (rmdir(h->fullcgpath) < 0)
+               SYSERROR("Failed to clean up cgroup %s from failed creation attempt", h->fullcgpath);
+       free(h->fullcgpath);
+       h->fullcgpath = NULL;
+}
+
+/*
+ * Try to create the same cgroup in all hierarchies.
+ * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
+ */
+static inline bool cgfsng_create(void *hdata)
+{
+       struct cgfsng_handler_data *d = hdata;
+       char *tmp, *cgname, *offset;
+       int i, idx = 0;
+       size_t len;
+
+       if (!d)
+               return false;
+       if (d->container_cgroup) {
+               WARN("cgfsng_create called a second time");
+               return false;
+       }
+
+       tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
+       if (!tmp) {
+               ERROR("Failed expanding cgroup name pattern");
+               return false;
+       }
+       len = strlen(tmp) + 5; // leave room for -NNN\0
+       cgname = must_alloc(len);
+       strcpy(cgname, tmp);
+       free(tmp);
+       offset = cgname + len - 5;
+
+again:
+       if (idx == 1000) {
+               ERROR("Too many conflicting cgroup names");
+               goto out_free;
+       }
+       if (idx)
+               snprintf(offset, 5, "-%d", idx);
+       for (i = 0; d->hierarchies[i]; i++) {
+               if (!create_path_for_hierarchy(d->hierarchies[i], cgname)) {
+                       int j;
+                       SYSERROR("Failed to create %s: %s", d->hierarchies[i]->fullcgpath, strerror(errno));
+                       free(d->hierarchies[i]->fullcgpath);
+                       d->hierarchies[i]->fullcgpath = NULL;
+                       for (j = 0; j < i; j++)
+                               remove_path_for_hierarchy(d->hierarchies[j], cgname);
+                       idx++;
+                       goto again;
+               }
+       }
+       /* Done */
+       d->container_cgroup = cgname;
+       return true;
+
+out_free:
+       free(cgname);
+       return false;
+}
+
+static const char *cgfsng_canonical_path(void *hdata)
+{
+       struct cgfsng_handler_data *d = hdata;
+
+       return d->container_cgroup;
+}
+
+static bool cgfsng_enter(void *hdata, pid_t pid)
+{
+       struct cgfsng_handler_data *d = hdata;
+       char pidstr[25];
+       int i, len;
+
+       len = snprintf(pidstr, 25, "%d", pid);
+       if (len < 0 || len > 25)
+               return false;
+
+       for (i = 0; d->hierarchies[i]; i++) {
+               char *fullpath = must_make_path(d->hierarchies[i]->fullcgpath,
+                                               "cgroup.procs", NULL);
+               if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
+                       SYSERROR("Failed to enter %s", fullpath);
+                       free(fullpath);
+                       return false;
+               }
+               free(fullpath);
+       }
+
+       return true;
+}
+
+struct chown_data {
+       struct cgfsng_handler_data *d;
+       uid_t origuid; // target uid in parent namespace
+};
+
+/*
+ * chgrp the container cgroups to container group.  We leave
+ * the container owner as cgroup owner.  So we must make the
+ * directories 775 so that the container can create sub-cgroups.
+ *
+ * Also chown the tasks and cgroup.procs files.  Those may not
+ * exist depending on kernel version.
+ */
+static int chown_cgroup_wrapper(void *data)
+{
+       struct chown_data *arg = data;
+       struct cgfsng_handler_data *d = arg->d;
+       uid_t destuid;
+       int i;
+
+       if (setresgid(0,0,0) < 0)
+               SYSERROR("Failed to setgid to 0");
+       if (setresuid(0,0,0) < 0)
+               SYSERROR("Failed to setuid to 0");
+       if (setgroups(0, NULL) < 0)
+               SYSERROR("Failed to clear groups");
+
+       destuid = get_ns_uid(arg->origuid);
+
+       for (i = 0; d->hierarchies[i]; i++) {
+               char *fullpath, *path = d->hierarchies[i]->fullcgpath;
+
+               if (chown(path, destuid, 0) < 0) {
+                       SYSERROR("Error chowning %s to %d", path, (int) destuid);
+                       return -1;
+               }
+
+               if (chmod(path, 0775) < 0) {
+                       SYSERROR("Error chmoding %s", path);
+                       return -1;
+               }
+
+               /*
+                * Failures to chown these are inconvenient but not detrimental
+                * We leave these owned by the container launcher, so that container
+                * root can write to the files to attach.  We chmod them 664 so that
+                * container systemd can write to the files (which systemd in wily
+                * insists on doing)
+                */
+               fullpath = must_make_path(path, "tasks", NULL);
+               if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
+                       WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
+               if (chmod(fullpath, 0664) < 0)
+                       WARN("Error chmoding %s: %m", path);
+               free(fullpath);
+
+               fullpath = must_make_path(path, "cgroup.procs", NULL);
+               if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
+                       WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
+               if (chmod(fullpath, 0664) < 0)
+                       WARN("Error chmoding %s: %m", path);
+               free(fullpath);
+       }
+
+       return 0;
+}
+
+static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
+{
+       struct cgfsng_handler_data *d = hdata;
+       struct chown_data wrap;
+
+       if (!d)
+               return false;
+
+       if (lxc_list_empty(&conf->id_map))
+               return true;
+
+       wrap.d = d;
+       wrap.origuid = geteuid();
+
+       if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
+               ERROR("Error requesting cgroup chown in new namespace");
+               return false;
+       }
+
+       return true;
+}
+
+/*
+ * We've safe-mounted a tmpfs as parent, so we don't need to protect against
+ * symlinks any more - just use mount
+ */
+
+/* mount cgroup-full if requested */
+static int mount_cgroup_full(int type, struct hierarchy *h, char *dest,
+                                  char *container_cgroup)
+{
+       if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
+               return 0;
+       if (mount(h->mountpoint, dest, "cgroup", MS_BIND, NULL) < 0) {
+               SYSERROR("Error bind-mounting %s cgroup onto %s", h->mountpoint,
+                        dest);
+               return -1;
+       }
+       if (type != LXC_AUTO_CGROUP_FULL_RW) {
+               unsigned long flags = MS_BIND | MS_NOSUID | MS_NOEXEC | MS_NODEV |
+                                     MS_REMOUNT | MS_RDONLY;
+               if (mount(NULL, dest, "cgroup", flags, NULL) < 0) {
+                       SYSERROR("Error remounting %s readonly", dest);
+                       return -1;
+               }
+       }
+
+       INFO("Bind mounted %s onto %s", h->mountpoint, dest);
+       if (type != LXC_AUTO_CGROUP_FULL_MIXED)
+               return 0;
+
+       /* mount just the container path rw */
+       char *source = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+       char *rwpath = must_make_path(dest, h->base_cgroup, container_cgroup, NULL);
+       if (mount(source, rwpath, "cgroup", MS_BIND, NULL) < 0)
+               WARN("Failed to mount %s read-write: %m", rwpath);
+       INFO("Made %s read-write", rwpath);
+       free(rwpath);
+       free(source);
+       return 0;
+}
+
+/* cgroup-full:* is done, no need to create subdirs */
+static bool cg_mount_needs_subdirs(int type)
+{
+       if (type >= LXC_AUTO_CGROUP_FULL_RO)
+               return false;
+       return true;
+}
+
+/*
+ * After $rootfs/sys/fs/container/controller/the/cg/path has been
+ * created, remount controller ro if needed and bindmount the
+ * cgroupfs onto controll/the/cg/path
+ */
+static int
+do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
+                               char *controllerpath, char *cgpath,
+                               const char *container_cgroup)
+{
+       if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
+               if (mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL) < 0) {
+                       SYSERROR("Error bind-mounting %s", controllerpath);
+                       return -1;
+               }
+               if (mount(controllerpath, controllerpath, "cgroup",
+                          MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) < 0) {
+                       SYSERROR("Error remounting %s read-only", controllerpath);
+                       return -1;
+               }
+               INFO("Remounted %s read-only", controllerpath);
+       }
+       char *sourcepath = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+       int flags = MS_BIND;
+       if (type == LXC_AUTO_CGROUP_RO)
+               flags |= MS_RDONLY;
+       INFO("Mounting %s onto %s", sourcepath, cgpath);
+       if (mount(sourcepath, cgpath, "cgroup", flags, NULL) < 0) {
+               free(sourcepath);
+               SYSERROR("Error mounting cgroup %s onto %s", h->controllers[0],
+                               cgpath);
+               return -1;
+       }
+       free(sourcepath);
+       INFO("Completed second stage cgroup automounts for %s", cgpath);
+       return 0;
+}
+
+static bool cgfsng_mount(void *hdata, const char *root, int type)
+{
+       struct cgfsng_handler_data *d = hdata;
+       char *tmpfspath = NULL;
+       bool retval = false;
+       int i;
+
+       if ((type & LXC_AUTO_CGROUP_MASK) == 0)
+               return true;
+
+       if (cgns_supported())
+               return true;
+
+       tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
+
+       if (type == LXC_AUTO_CGROUP_NOSPEC)
+               type = LXC_AUTO_CGROUP_MIXED;
+       else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
+               type = LXC_AUTO_CGROUP_FULL_MIXED;
+
+       /* Mount tmpfs */
+       if (safe_mount("cgroup_root", tmpfspath, "tmpfs",
+                       MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
+                       "size=10240k,mode=755",
+                       root) < 0)
+               goto  bad;
+
+       for (i = 0; d->hierarchies[i]; i++) {
+               char *controllerpath, *path2;
+               struct hierarchy *h = d->hierarchies[i];
+               char *controller = strrchr(h->mountpoint, '/');
+               int r;
+
+               if (!controller)
+                       continue;
+               controller++;
+               controllerpath = must_make_path(tmpfspath, controller, NULL);
+               if (dir_exists(controllerpath)) {
+                       free(controllerpath);
+                       continue;
+               }
+               if (mkdir(controllerpath, 0755) < 0) {
+                       SYSERROR("Error creating cgroup path: %s", controllerpath);
+                       free(controllerpath);
+                       goto bad;
+               }
+               if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
+                       free(controllerpath);
+                       goto bad;
+               }
+               if (!cg_mount_needs_subdirs(type)) {
+                       free(controllerpath);
+                       continue;
+               }
+               path2 = must_make_path(controllerpath, h->base_cgroup, d->container_cgroup, NULL);
+               if (mkdir_p(path2, 0755) < 0) {
+                       free(controllerpath);
+                       goto bad;
+               }
+               
+               r = do_secondstage_mounts_if_needed(type, h, controllerpath, path2,
+                                                   d->container_cgroup);
+               free(controllerpath);
+               free(path2);
+               if (r < 0)
+                       goto bad;
+       }
+       retval = true;
+
+bad:
+       free(tmpfspath);
+       return retval;
+}
+
+static int recursive_count_nrtasks(char *dirname)
+{
+       struct dirent dirent, *direntp;
+       DIR *dir;
+       int count = 0, ret;
+       char *path;
+
+       dir = opendir(dirname);
+       if (!dir)
+               return 0;
+
+       while (!readdir_r(dir, &dirent, &direntp)) {
+               struct stat mystat;
+
+               if (!direntp)
+                       break;
+
+               if (!strcmp(direntp->d_name, ".") ||
+                   !strcmp(direntp->d_name, ".."))
+                       continue;
+
+               path = must_make_path(dirname, direntp->d_name, NULL);
+
+               if (lstat(path, &mystat))
+                       goto next;
+
+               if (!S_ISDIR(mystat.st_mode))
+                       goto next;
+
+               count += recursive_count_nrtasks(path);
+next:
+               free(path);
+       }
+
+       path = must_make_path(dirname, "cgroup.procs", NULL);
+       ret = lxc_count_file_lines(path);
+       if (ret != -1)
+               count += ret;
+       free(path);
+
+       (void) closedir(dir);
+
+       return count;
+}
+
+static int cgfsng_nrtasks(void *hdata) {
+       struct cgfsng_handler_data *d = hdata;
+       char *path;
+       int count;
+
+       if (!d || !d->container_cgroup || !d->hierarchies)
+               return -1;
+       path = must_make_path(d->hierarchies[0]->fullcgpath, NULL);
+       count = recursive_count_nrtasks(path);
+       free(path);
+       return count;
+}
+
+/* Only root needs to escape to the cgroup of its init */
+static bool cgfsng_escape()
+{
+       struct cgfsng_handler_data *d;
+       int i;
+       bool ret = false;
+
+       if (geteuid())
+               return true;
+
+       d = cgfsng_init("criu-temp-cgfsng");
+       if (!d) {
+               ERROR("cgfsng_init failed");
+               return false;
+       }
+
+       for (i = 0; d->hierarchies[i]; i++) {
+               char *fullpath = must_make_path(d->hierarchies[i]->mountpoint,
+                                               d->hierarchies[i]->base_cgroup,
+                                               "cgroup.procs", NULL);
+               if (lxc_write_to_file(fullpath, "0", 2, false) != 0) {
+                       SYSERROR("Failed to escape to %s", fullpath);
+                       free(fullpath);
+                       goto out;
+               }
+               free(fullpath);
+       }
+
+       ret = true;
+out:
+       free_handler_data(d);
+       return ret;
+}
+
+#define THAWED "THAWED"
+#define THAWED_LEN (strlen(THAWED))
+
+static bool cgfsng_unfreeze(void *hdata)
+{
+       struct cgfsng_handler_data *d = hdata;
+       char *fullpath;
+       struct hierarchy *h = get_hierarchy(d, "freezer");
+
+       if (!d || !h)
+               return false;
+       fullpath = must_make_path(h->fullcgpath, "freezer.state", NULL);
+       if (lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false) != 0) {
+               free(fullpath);
+               return false;
+       }
+       free(fullpath);
+       return true;
+}
+
+static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
+{
+       struct cgfsng_handler_data *d = hdata;
+       struct hierarchy *h;
+       if (!d)
+               return NULL;
+
+       h = get_hierarchy(d, subsystem);
+       if (!h)
+               return NULL;
+
+       return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
+}
+
+/*
+ * Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a
+ * full path, which must be freed by the caller.
+ */
+static char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
+                                               const char *inpath,
+                                               const char *filename)
+{
+       /*
+        * XXX Remove this case after 2.0 release.  It's for dealing with
+        * containers spawned under the old buggy cgfsng which wasn't around
+        * for long.
+        */
+       if (strncmp(inpath, "/sys/fs/cgroup/", 15) == 0)
+               return must_make_path(inpath, filename, NULL);
+       return must_make_path(h->mountpoint, inpath, filename, NULL);
+}
+
+static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+       struct cgfsng_handler_data *d;
+       char pidstr[25];
+       int i, len;
+
+       len = snprintf(pidstr, 25, "%d", pid);
+       if (len < 0 || len > 25)
+               return false;
+
+       d = cgfsng_init(name);
+       if (!d)
+               return false;
+
+       for (i = 0; d->hierarchies[i]; i++) {
+               char *path, *fullpath;
+               struct hierarchy *h = d->hierarchies[i];
+
+               path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
+               if (!path) // not running
+                       continue;
+
+               fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
+               free(path);
+               if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
+                       SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
+                       free(fullpath);
+                       free_handler_data(d);
+                       return false;
+               }
+               free(fullpath);
+       }
+
+       free_handler_data(d);
+       return true;
+}
+
+/*
+ * Called externally (i.e. from 'lxc-cgroup') to query cgroup limits.
+ * Here we don't have a cgroup_data set up, so we ask the running
+ * container through the commands API for the cgroup path
+ */
+static int cgfsng_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+       char *subsystem, *p, *path;
+       struct cgfsng_handler_data *d;
+       struct hierarchy *h;
+       int ret = -1;
+
+       subsystem = alloca(strlen(filename) + 1);
+       strcpy(subsystem, filename);
+       if ((p = strchr(subsystem, '.')) != NULL)
+               *p = '\0';
+
+       path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
+       if (!path) // not running
+               return -1;
+
+       d = cgfsng_init(name);
+       if (!d) {
+               free(path);
+               return false;
+       }
+
+       h = get_hierarchy(d, subsystem);
+       if (h) {
+               char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
+               ret = lxc_read_from_file(fullpath, value, len);
+               free(fullpath);
+       }
+
+       free_handler_data(d);
+       free(path);
+
+       return ret;
+}
+
+/*
+ * Called externally (i.e. from 'lxc-cgroup') to set new cgroup limits.
+ * Here we don't have a cgroup_data set up, so we ask the running
+ * container through the commands API for the cgroup path
+ */
+static int cgfsng_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+       char *subsystem, *p, *path;
+       struct cgfsng_handler_data *d;
+       struct hierarchy *h;
+       int ret = -1;
+
+       subsystem = alloca(strlen(filename) + 1);
+       strcpy(subsystem, filename);
+       if ((p = strchr(subsystem, '.')) != NULL)
+               *p = '\0';
+
+       path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
+       if (!path) // not running
+               return -1;
+
+       d = cgfsng_init(name);
+       if (!d) {
+               free(path);
+               return false;
+       }
+
+       h = get_hierarchy(d, subsystem);
+       if (h) {
+               char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
+               ret = lxc_write_to_file(fullpath, value, strlen(value), false);
+               free(fullpath);
+       }
+
+       free_handler_data(d);
+       free(path);
+
+       return ret;
+}
+
+/*
+ * Called from setup_limits - here we have the container's cgroup_data because
+ * we created the cgroups
+ */
+static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfsng_handler_data *d)
+{
+       char *subsystem = NULL, *p;
+       int ret = -1;
+       struct hierarchy *h;
+
+       subsystem = alloca(strlen(filename) + 1);
+       strcpy(subsystem, filename);
+       if ((p = strchr(subsystem, '.')) != NULL)
+               *p = '\0';
+
+       h = get_hierarchy(d, subsystem);
+       if (h) {
+               char *fullpath = must_make_path(h->fullcgpath, filename, NULL);
+               ret = lxc_write_to_file(fullpath, value, strlen(value), false);
+               free(fullpath);
+       }
+       return ret;
+}
+
+static bool cgfsng_setup_limits(void *hdata, struct lxc_list *cgroup_settings,
+                                 bool do_devices)
+{
+       struct cgfsng_handler_data *d = hdata;
+       struct lxc_list *iterator, *sorted_cgroup_settings, *next;
+       struct lxc_cgroup *cg;
+       struct hierarchy *h;
+       char *listpath = NULL;
+       bool ret = false;
+
+       if (lxc_list_empty(cgroup_settings))
+               return true;
+
+       sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+       if (!sorted_cgroup_settings) {
+               return false;
+       }
+
+       if (do_devices) {
+               h = get_hierarchy(d, "devices");
+               if (!h) {
+                       ERROR("No devices cgroup setup for %s", d->name);
+                       return false;
+               }
+               listpath = must_make_path(h->fullcgpath, "devices.list", NULL);
+       }
+
+       lxc_list_for_each(iterator, sorted_cgroup_settings) {
+               cg = iterator->elem;
+
+               if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
+                       if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
+                               if (do_devices && (errno == EACCES || errno == EPERM)) {
+                                       WARN("Error setting %s to %s for %s",
+                                             cg->subsystem, cg->value, d->name);
+                                       continue;
+                               }
+                               SYSERROR("Error setting %s to %s for %s",
+                                     cg->subsystem, cg->value, d->name);
+                               goto out;
+                       }
+               }
+
+               DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
+       }
+
+       ret = true;
+       INFO("cgroup has been setup");
+out:
+       free(listpath);
+       lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+               lxc_list_del(iterator);
+               free(iterator);
+       }
+       free(sorted_cgroup_settings);
+       return ret;
+}
+
+static struct cgroup_ops cgfsng_ops = {
+       .init = cgfsng_init,
+       .destroy = cgfsng_destroy,
+       .create = cgfsng_create,
+       .enter = cgfsng_enter,
+       .canonical_path = cgfsng_canonical_path,
+       .escape = cgfsng_escape,
+       .get_cgroup = cgfsng_get_cgroup,
+       .get = cgfsng_get,
+       .set = cgfsng_set,
+       .unfreeze = cgfsng_unfreeze,
+       .setup_limits = cgfsng_setup_limits,
+       .name = "cgroupfs-ng",
+       .attach = cgfsng_attach,
+       .chown = cgfsns_chown,
+       .mount_cgroup = cgfsng_mount,
+       .nrtasks = cgfsng_nrtasks,
+       .driver = CGFSNG,
+
+       /* unsupported */
+       .create_legacy = NULL,
+};
index f868903..c387b00 100644 (file)
@@ -46,7 +46,7 @@
 #include "list.h"
 #include "conf.h"
 #include "utils.h"
-#include "bdev.h"
+#include "bdev/bdev.h"
 #include "log.h"
 #include "cgroup.h"
 #include "start.h"
@@ -183,11 +183,6 @@ static bool cgm_dbus_connect(void)
        return true;
 }
 
-static bool cgm_supports_multiple_controllers;
-/*
- * if cgm_all_controllers_same is true, then cgm_supports_multiple_controllers
- * is true
- */
 static bool cgm_all_controllers_same;
 
 /*
@@ -207,16 +202,8 @@ static void check_supports_multiple_controllers(pid_t pid)
        size_t sz = 0;
        char path[100];
 
-       cgm_supports_multiple_controllers = false;
        cgm_all_controllers_same = false;
 
-       if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS) {
-               cgm_supports_multiple_controllers = false;
-               return;
-       }
-
-       cgm_supports_multiple_controllers = true;
-
        if (pid == -1)
                sprintf(path, "/proc/self/cgroup");
        else
@@ -312,13 +299,22 @@ static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path
  * be in "/lxc/c1" rather than "/user/..../c1"
  * called internally with connection already open
  */
-static bool lxc_cgmanager_escape(void)
+static bool cgm_escape(void *hdata)
 {
-       bool ret = true;
+       bool ret = true, cgm_needs_disconnect = false;
        pid_t me = getpid();
        char **slist = subsystems;
        int i;
 
+       if (!cgroup_manager) {
+               if (!cgm_dbus_connect()) {
+                       ERROR("Error connecting to cgroup manager");
+                       return false;
+               }
+               cgm_needs_disconnect = true;
+       }
+
+
        if (cgm_all_controllers_same)
                slist = subsystems_inone;
 
@@ -335,6 +331,9 @@ static bool lxc_cgmanager_escape(void)
                }
        }
 
+       if (cgm_needs_disconnect)
+               cgm_dbus_disconnect();
+
        return ret;
 }
 
@@ -438,7 +437,7 @@ static int chown_cgroup_wrapper(void *data)
        }
        destuid = get_ns_uid(arg->origuid);
 
-       if (cgm_supports_multiple_controllers)
+       if (cgm_all_controllers_same)
                slist = subsystems_inone;
 
        for (i = 0; slist[i]; i++) {
@@ -496,15 +495,15 @@ static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf)
         * This can't be done in the child namespace because it only group-owns
         * the cgroup
         */
-       if (cgm_supports_multiple_controllers)
+       if (cgm_all_controllers_same)
                slist = subsystems_inone;
 
        for (i = 0; slist[i]; i++) {
                if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "", 0775))
                        return false;
-               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "tasks", 0775))
+               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "tasks", 0664))
                        return false;
-               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "cgroup.procs", 0775))
+               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "cgroup.procs", 0664))
                        return false;
        }
 
@@ -532,17 +531,13 @@ static void *cgm_init(const char *name)
 {
        struct cgm_data *d;
 
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return NULL;
-       }
-
-       check_supports_multiple_controllers(-1);
-
        d = malloc(sizeof(*d));
-       if (!d) {
-               cgm_dbus_disconnect();
+       if (!d)
                return NULL;
+
+       if (!cgm_dbus_connect()) {
+               ERROR("Error connecting to cgroup manager");
+               goto err1;
        }
 
        memset(d, 0, sizeof(*d));
@@ -563,7 +558,7 @@ err1:
 }
 
 /* Called after a failed container startup */
-static void cgm_destroy(void *hdata)
+static void cgm_destroy(void *hdata, struct lxc_conf *conf)
 {
        struct cgm_data *d = hdata;
        char **slist = subsystems;
@@ -576,7 +571,7 @@ static void cgm_destroy(void *hdata)
                return;
        }
 
-       if (cgm_supports_multiple_controllers)
+       if (cgm_all_controllers_same)
                slist = subsystems_inone;
        for (i = 0; slist[i]; i++)
                cgm_remove_cgroup(slist[i], d->cgroup_path);
@@ -596,7 +591,7 @@ static inline void cleanup_cgroups(char *path)
        int i;
        char **slist = subsystems;
 
-       if (cgm_supports_multiple_controllers)
+       if (cgm_all_controllers_same)
                slist = subsystems_inone;
        for (i = 0; slist[i]; i++)
                cgm_remove_cgroup(slist[i], path);
@@ -642,7 +637,7 @@ again:
        }
        existed = 0;
 
-       if (cgm_supports_multiple_controllers)
+       if (cgm_all_controllers_same)
                slist = subsystems_inone;
 
        for (i = 0; slist[i]; i++) {
@@ -694,7 +689,7 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
        if (ret != 0) {
                NihError *nerr;
                nerr = nih_error_get();
-               ERROR("call to cgmanager_move_pid_%ssync failed: %s",
+               WARN("call to cgmanager_move_pid_%ssync failed: %s",
                        abs ? "abs_" : "", nerr->message);
                nih_free(nerr);
                return false;
@@ -775,8 +770,8 @@ static char *try_get_abs_cgroup(const char *name, const char *lxcpath,
                        NihError *nerr;
                        nerr = nih_error_get();
                        nih_free(nerr);
-               }
-               prune_init_scope(cgroup);
+               } else
+                       prune_init_scope(cgroup);
                return cgroup;
        }
 
@@ -899,7 +894,7 @@ static void do_cgm_get(const char *name, const char *lxcpath, const char *filena
        }
        *cglast = '\0';
        if (!lxc_cgmanager_enter(getpid(), controller, cgroup, abs_cgroup_supported())) {
-               ERROR("Failed to enter container cgroup %s:%s", controller, cgroup);
+               WARN("Failed to enter container cgroup %s:%s", controller, cgroup);
                ret = write(outp, &len, sizeof(len));
                if (ret != sizeof(len))
                        WARN("Failed to warn cgm_get of error; parent may hang");
@@ -1120,6 +1115,9 @@ static void cull_user_controllers(void)
        }
 }
 
+/*
+ * return true if inword is in the comma-delimited list cgroup_use
+ */
 static bool in_comma_list(const char *inword, const char *cgroup_use)
 {
        char *e;
@@ -1136,6 +1134,23 @@ static bool in_comma_list(const char *inword, const char *cgroup_use)
        return false;
 }
 
+/*
+ * inlist is a comma-delimited list of cgroups;  so is checklist.  Return
+ * true if any member of inlist is in checklist.
+ */
+static bool any_in_comma_list(const char *inlist, const char *checklist)
+{
+       char *tmp = alloca(strlen(inlist) + 1), *tok, *saveptr = NULL;
+
+       strcpy(tmp, inlist);
+       for (tok = strtok_r(tmp, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr)) {
+               if (in_comma_list(tok, checklist))
+                       return true;
+       }
+
+       return false;
+}
+
 static bool in_subsystem_list(const char *c)
 {
        int i;
@@ -1190,7 +1205,119 @@ static bool verify_and_prune(const char *cgroup_use)
        return true;
 }
 
-static bool collect_subsytems(void)
+static void drop_subsystem(int which)
+{
+       int i;
+
+       if (which < 0 || which >= nr_subsystems) {
+               ERROR("code error: dropping invalid subsystem index\n");
+               exit(1);
+       }
+
+       free(subsystems[which]);
+       /* note - we have nr_subsystems+1 entries, last one a NULL */
+       for (i = which; i < nr_subsystems; i++)
+               subsystems[i] = subsystems[i+1];
+       nr_subsystems -= 1;
+}
+
+/*
+ * Check whether we can create the cgroups we would want
+ */
+static bool subsys_is_writeable(const char *controller, const char *probe)
+{
+       int32_t existed;
+       bool ret = true;
+
+       if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
+                                      probe, &existed) != 0) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
+               nih_free(nerr);
+               ERROR("Failed to create %s:%s", controller, probe);
+               ret = false;
+       }
+
+       return ret;
+}
+
+static char *get_last_controller_in_list(char *list)
+{
+       char *p;
+
+       while ((p = strchr(list, ',')) != NULL)
+               list = p + 1;
+
+       return list;
+}
+
+/*
+ * Make sure that all the controllers are writeable.
+ * If any are not, then
+ *   - if they are listed in lxc.cgroup.use, refuse to start
+ *   - else if they are crucial subsystems, refuse to start
+ *   - else warn and do not use them
+ */
+static bool verify_final_subsystems(const char *cgroup_use)
+{
+       int i;
+       bool dropped_any = false;
+       bool bret = false;
+       const char *cgroup_pattern;
+       char tmpnam[50], *probe;
+
+       if (!cgm_dbus_connect()) {
+               ERROR("Error connecting to cgroup manager");
+               return false;
+       }
+
+       cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+       i = snprintf(tmpnam, 50, "lxcprobe-%d", getpid());
+       if (i < 0 || i >= 50) {
+               ERROR("Attack - format string modified?");
+               return false;
+       }
+       probe = lxc_string_replace("%n", tmpnam, cgroup_pattern);
+       if (!probe)
+               goto out;
+
+       i = 0;
+       while (i < nr_subsystems) {
+               char *p = get_last_controller_in_list(subsystems[i]);
+
+               if (!subsys_is_writeable(p, probe)) {
+                       if (is_crucial_cgroup_subsystem(p)) {
+                               ERROR("Cannot write to crucial subsystem %s\n",
+                                       subsystems[i]);
+                               goto out;
+                       }
+                       if (cgroup_use && any_in_comma_list(subsystems[i], cgroup_use)) {
+                               ERROR("Cannot write to subsystem %s which is requested in lxc.cgroup.use\n",
+                                       subsystems[i]);
+                               goto out;
+                       }
+                       WARN("Cannot write to subsystem %s, continuing with out it\n",
+                               subsystems[i]);
+                       dropped_any = true;
+                       drop_subsystem(i);
+               } else {
+                       cgm_remove_cgroup(subsystems[i], probe);
+                       i++;
+               }
+       }
+
+       if (dropped_any)
+               cgm_all_controllers_same = false;
+       bret = true;
+
+out:
+       free(probe);
+       cgm_dbus_disconnect();
+       return bret;
+}
+
+static bool collect_subsystems(void)
 {
        char *line = NULL;
        nih_local char **cgm_subsys_list = NULL;
@@ -1273,7 +1400,7 @@ collected:
        /* make sure that cgroup.use can be and is honored */
        const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use");
        if (!cgroup_use && errno != 0)
-               goto out_good;
+               goto final_verify;
        if (cgroup_use) {
                if (!verify_and_prune(cgroup_use)) {
                        free_subsystems();
@@ -1283,8 +1410,8 @@ collected:
                cgm_all_controllers_same = false;
        }
 
-out_good:
-       return true;
+final_verify:
+       return verify_final_subsystems(cgroup_use);
 
 out_free:
        free(line);
@@ -1301,23 +1428,20 @@ out_free:
  */
 struct cgroup_ops *cgm_ops_init(void)
 {
-       if (!collect_subsytems())
+       check_supports_multiple_controllers(-1);
+       if (!collect_subsystems())
                return NULL;
-       if (!cgm_dbus_connect())
-               goto err1;
 
-       // root;  try to escape to root cgroup
-       if (geteuid() == 0 && !lxc_cgmanager_escape())
-               goto err2;
-       cgm_dbus_disconnect();
+       if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
+               cgm_all_controllers_same = false;
 
-       return &cgmanager_ops;
+       // if root, try to escape to root cgroup
+       if (geteuid() == 0 && !cgm_escape(NULL)) {
+               free_subsystems();
+               return NULL;
+       }
 
-err2:
-       cgm_dbus_disconnect();
-err1:
-       free_subsystems();
-       return NULL;
+       return &cgmanager_ops;
 }
 
 /* unfreeze is called by the command api after killing a container.  */
@@ -1384,6 +1508,14 @@ static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool
                                         d->cgroup_path, cg->subsystem, cg->value) != 0) {
                        NihError *nerr;
                        nerr = nih_error_get();
+                       if (do_devices) {
+                               WARN("call to cgmanager_set_value_sync failed: %s", nerr->message);
+                               nih_free(nerr);
+                               WARN("Error setting cgroup %s:%s limit type %s", controller,
+                                       d->cgroup_path, cg->subsystem);
+                               continue;
+                       }
+
                        ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
                        nih_free(nerr);
                        ERROR("Error setting cgroup %s:%s limit type %s", controller,
@@ -1524,6 +1656,7 @@ static struct cgroup_ops cgmanager_ops = {
        .create_legacy = NULL,
        .get_cgroup = cgm_get_cgroup,
        .canonical_path = cgm_canonical_path,
+       .escape = cgm_escape,
        .get = cgm_get,
        .set = cgm_set,
        .unfreeze = cgm_unfreeze,
index b1c764f..1a92ef4 100644 (file)
@@ -34,6 +34,7 @@ lxc_log_define(lxc_cgroup, lxc);
 static struct cgroup_ops *ops = NULL;
 
 extern struct cgroup_ops *cgfs_ops_init(void);
+extern struct cgroup_ops *cgfsng_ops_init(void);
 extern struct cgroup_ops *cgm_ops_init(void);
 
 __attribute__((constructor))
@@ -49,6 +50,8 @@ void cgroup_ops_init(void)
        ops = cgm_ops_init();
        #endif
        if (!ops)
+               ops = cgfsng_ops_init();
+       if (!ops)
                ops = cgfs_ops_init();
        if (ops)
                INFO("Initialized cgroup driver %s", ops->name);
@@ -71,7 +74,7 @@ bool cgroup_init(struct lxc_handler *handler)
 void cgroup_destroy(struct lxc_handler *handler)
 {
        if (ops) {
-               ops->destroy(handler->cgroup_data);
+               ops->destroy(handler->cgroup_data, handler->conf);
                handler->cgroup_data = NULL;
        }
 }
@@ -109,6 +112,13 @@ const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem
        return NULL;
 }
 
+bool cgroup_escape(struct lxc_handler *handler)
+{
+       if (ops)
+               return ops->escape(handler->cgroup_data);
+       return false;
+}
+
 const char *cgroup_canonical_path(struct lxc_handler *handler)
 {
        if (geteuid()) {
@@ -198,7 +208,12 @@ cgroup_driver_t cgroup_driver(void)
 #define INIT_SCOPE "/init.scope"
 void prune_init_scope(char *cg)
 {
-       char *point = cg + strlen(cg) - strlen(INIT_SCOPE);
+       char *point;
+
+       if (!cg)
+               return;
+
+       point = cg + strlen(cg) - strlen(INIT_SCOPE);
        if (point < cg)
                return;
        if (strcmp(point, INIT_SCOPE) == 0) {
@@ -208,3 +223,18 @@ void prune_init_scope(char *cg)
                        *point = '\0';
        }
 }
+
+/*
+ * Return true if this is a subsystem which we cannot do
+ * without
+ */
+bool is_crucial_cgroup_subsystem(const char *s)
+{
+       if (strcmp(s, "systemd") == 0)
+               return true;
+       if (strcmp(s, "name=systemd") == 0)
+               return true;
+       if (strcmp(s, "freezer") == 0)
+               return true;
+       return false;
+}
index 7704c04..e56a115 100644 (file)
@@ -35,18 +35,20 @@ struct lxc_list;
 typedef enum {
        CGFS,
        CGMANAGER,
+       CGFSNG,
 } cgroup_driver_t;
 
 struct cgroup_ops {
        const char *name;
 
        void *(*init)(const char *name);
-       void (*destroy)(void *hdata);
+       void (*destroy)(void *hdata, struct lxc_conf *conf);
        bool (*create)(void *hdata);
        bool (*enter)(void *hdata, pid_t pid);
        bool (*create_legacy)(void *hdata, pid_t pid);
        const char *(*get_cgroup)(void *hdata, const char *subsystem);
        const char *(*canonical_path)(void *hdata);
+       bool (*escape)();
        int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
        int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
        bool (*unfreeze)(void *hdata);
@@ -71,6 +73,7 @@ extern void cgroup_cleanup(struct lxc_handler *handler);
 extern bool cgroup_create_legacy(struct lxc_handler *handler);
 extern int cgroup_nrtasks(struct lxc_handler *handler);
 extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
+extern bool cgroup_escape();
 
 /*
  * Currently, this call  only makes sense for privileged containers.
@@ -81,5 +84,6 @@ extern void cgroup_disconnect(void);
 extern cgroup_driver_t cgroup_driver(void);
 
 extern void prune_init_scope(char *cg);
+extern bool is_crucial_cgroup_subsystem(const char *s);
 
 #endif
index 55c2fae..3b023ef 100644 (file)
@@ -20,6 +20,8 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+
+#define _GNU_SOURCE
 #include "config.h"
 
 #include <stdio.h>
@@ -36,6 +38,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <time.h>
+
 #ifdef HAVE_STATVFS
 #include <sys/statvfs.h>
 #endif
@@ -71,7 +74,9 @@
 #include "conf.h"
 #include "log.h"
 #include "caps.h"       /* for lxc_caps_last_cap() */
-#include "bdev.h"
+#include "bdev/bdev.h"
+#include "bdev/lxcaufs.h"
+#include "bdev/lxcoverlay.h"
 #include "cgroup.h"
 #include "lxclock.h"
 #include "namespace.h"
@@ -163,7 +168,7 @@ return -1;
 #endif
 
 char *lxchook_names[NUM_LXC_HOOKS] = {
-       "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" };
+       "pre-start", "pre-mount", "mount", "autodev", "start", "stop", "post-stop", "clone", "destroy" };
 
 typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
 
@@ -452,97 +457,6 @@ static int run_script(const char *name, const char *section,
        return run_buffer(buffer);
 }
 
-static int find_fstype_cb(char* buffer, void *data)
-{
-       struct cbarg {
-               const char *rootfs;
-               const char *target;
-               const char *options;
-       } *cbarg = data;
-
-       unsigned long mntflags;
-       char *mntdata;
-       char *fstype;
-
-       /* we don't try 'nodev' entries */
-       if (strstr(buffer, "nodev"))
-               return 0;
-
-       fstype = buffer;
-       fstype += lxc_char_left_gc(fstype, strlen(fstype));
-       fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
-
-       /* ignore blank line and comment */
-       if (fstype[0] == '\0' || fstype[0] == '#')
-               return 0;
-
-       DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
-             cbarg->rootfs, cbarg->target, fstype);
-
-       if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -1;
-       }
-
-       if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
-               DEBUG("mount failed with error: %s", strerror(errno));
-               free(mntdata);
-               return 0;
-       }
-       free(mntdata);
-
-       INFO("mounted '%s' on '%s', with fstype '%s'",
-            cbarg->rootfs, cbarg->target, fstype);
-
-       return 1;
-}
-
-static int mount_unknown_fs(const char *rootfs, const char *target,
-                                       const char *options)
-{
-       int i;
-
-       struct cbarg {
-               const char *rootfs;
-               const char *target;
-               const char *options;
-       } cbarg = {
-               .rootfs = rootfs,
-               .target = target,
-               .options = options,
-       };
-
-       /*
-        * find the filesystem type with brute force:
-        * first we check with /etc/filesystems, in case the modules
-        * are auto-loaded and fall back to the supported kernel fs
-        */
-       char *fsfile[] = {
-               "/etc/filesystems",
-               "/proc/filesystems",
-       };
-
-       for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
-
-               int ret;
-
-               if (access(fsfile[i], F_OK))
-                       continue;
-
-               ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
-               if (ret < 0) {
-                       ERROR("failed to parse '%s'", fsfile[i]);
-                       return -1;
-               }
-
-               if (ret)
-                       return 0;
-       }
-
-       ERROR("failed to determine fs type for '%s'", rootfs);
-       return -1;
-}
-
 static int mount_rootfs_dir(const char *rootfs, const char *target,
                                        const char *options)
 {
@@ -805,6 +719,7 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
                        }
                        if (!default_mounts[i].destination) {
                                ERROR("BUG: auto mounts destination %d was NULL", i);
+                               free(source);
                                return -1;
                        }
                        /* will act like strdup if %r is not present */
@@ -1083,7 +998,7 @@ static int setup_tty(struct lxc_conf *conf)
 }
 
 
-static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
+static int setup_rootfs_pivot_root(const char *rootfs)
 {
        int oldroot = -1, newroot = -1;
 
@@ -1170,10 +1085,11 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, cons
                return 0;
        }
 
-       if (safe_mount("none", path, "tmpfs", 0, "size=100000,mode=755",
-                               rootfs->path ? rootfs->mount : NULL)) {
+       ret = safe_mount("none", path, "tmpfs", 0, "size=500000,mode=755",
+                       rootfs->path ? rootfs->mount : NULL);
+       if (ret != 0) {
                SYSERROR("Failed mounting tmpfs onto %s\n", path);
-               return false;
+               return -1;
        }
 
        INFO("Mounted tmpfs onto %s",  path);
@@ -1215,7 +1131,7 @@ static const struct lxc_devs lxc_devs[] = {
        { "console",    S_IFCHR | S_IRUSR | S_IWUSR,           5, 1     },
 };
 
-static int fill_autodev(const struct lxc_rootfs *rootfs)
+static int fill_autodev(const struct lxc_rootfs *rootfs, bool mount_console)
 {
        int ret;
        char path[MAXPATHLEN];
@@ -1230,13 +1146,17 @@ static int fill_autodev(const struct lxc_rootfs *rootfs)
                return -1;
        }
 
-       if (!dir_exists(path))  // ignore, just don't try to fill in
+       if (!dir_exists(path)) // ignore, just don't try to fill in
                return 0;
 
        INFO("Populating container /dev");
        cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
        for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
                const struct lxc_devs *d = &lxc_devs[i];
+
+               if (!strcmp(d->name, "console") && !mount_console)
+                       continue;
+
                ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", rootfs->path ? rootfs->mount : "", d->name);
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
@@ -1404,7 +1324,7 @@ static int setup_pivot_root(const struct lxc_rootfs *rootfs)
        if (detect_ramfs_rootfs()) {
                if (prepare_ramfs_root(rootfs->mount))
                        return -1;
-       } else if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
+       } else if (setup_rootfs_pivot_root(rootfs->mount)) {
                ERROR("failed to setup pivot root");
                return -1;
        }
@@ -1480,8 +1400,7 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs,
                         const struct lxc_console *console)
 {
        char path[MAXPATHLEN];
-       struct stat s;
-       int ret;
+       int ret, fd;
 
        ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
        if (ret >= sizeof(path)) {
@@ -1489,9 +1408,14 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs,
                return -1;
        }
 
-       if (access(path, F_OK)) {
-               WARN("rootfs specified but no console found at '%s'", path);
-               return 0;
+       fd = open(path, O_CREAT | O_EXCL, S_IXUSR | S_IXGRP | S_IXOTH);
+       if (fd < 0) {
+               if (errno != EEXIST) {
+                       SYSERROR("failed to create console");
+                       return -1;
+               }
+       } else {
+               close(fd);
        }
 
        if (console->master < 0) {
@@ -1499,14 +1423,9 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs,
                return 0;
        }
 
-       if (stat(path, &s)) {
-               SYSERROR("failed to stat '%s'", path);
-               return -1;
-       }
-
-       if (chmod(console->name, s.st_mode)) {
+       if (chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH)) {
                SYSERROR("failed to set mode '0%o' to '%s'",
-                        s.st_mode, console->name);
+                        S_IXUSR | S_IXGRP | S_IXOTH, console->name);
                return -1;
        }
 
@@ -1815,169 +1734,6 @@ static void cull_mntent_opt(struct mntent *mntent)
        }
 }
 
-static char *ovl_get_rootfs_dir(const char *rootfs_path, size_t *rootfslen)
-{
-       char *rootfsdir = NULL;
-       char *s1 = NULL;
-       char *s2 = NULL;
-       char *s3 = NULL;
-
-       if (!rootfs_path || !rootfslen)
-               return NULL;
-
-       s1 = strdup(rootfs_path);
-       if (!s1)
-               return NULL;
-
-       if ((s2 = strstr(s1, ":/"))) {
-               s2 = s2 + 1;
-               if ((s3 = strstr(s2, ":/")))
-                       *s3 = '\0';
-               rootfsdir = strdup(s2);
-               if (!rootfsdir) {
-                       free(s1);
-                       return NULL;
-               }
-       }
-
-       if (!rootfsdir)
-               rootfsdir = s1;
-       else
-               free(s1);
-
-       *rootfslen = strlen(rootfsdir);
-
-       return rootfsdir;
-}
-
-static int mount_entry_create_overlay_dirs(const struct mntent *mntent,
-                                          const struct lxc_rootfs *rootfs,
-                                          const char *lxc_name,
-                                          const char *lxc_path)
-{
-       char lxcpath[MAXPATHLEN];
-       char *rootfsdir = NULL;
-       char *upperdir = NULL;
-       char *workdir = NULL;
-       char **opts = NULL;
-       int fret = -1;
-       int ret = 0;
-       size_t arrlen = 0;
-       size_t dirlen = 0;
-       size_t i;
-       size_t len = 0;
-       size_t rootfslen = 0;
-
-       if (!rootfs->path || !lxc_name || !lxc_path)
-               goto err;
-
-       opts = lxc_string_split(mntent->mnt_opts, ',');
-       if (opts)
-               arrlen = lxc_array_len((void **)opts);
-       else
-               goto err;
-
-       for (i = 0; i < arrlen; i++) {
-               if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
-                       upperdir = opts[i] + len;
-               else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
-                       workdir = opts[i] + len;
-       }
-
-       ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               goto err;
-
-       rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen);
-       if (!rootfsdir)
-               goto err;
-
-       dirlen = strlen(lxcpath);
-
-       /* We neither allow users to create upperdirs and workdirs outside the
-        * containerdir nor inside the rootfs. The latter might be debatable. */
-       if (upperdir)
-               if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
-                       if (mkdir_p(upperdir, 0755) < 0) {
-                               WARN("Failed to create upperdir");
-                       }
-
-       if (workdir)
-               if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
-                       if (mkdir_p(workdir, 0755) < 0) {
-                               WARN("Failed to create workdir");
-                       }
-
-       fret = 0;
-
-err:
-       free(rootfsdir);
-       lxc_free_array((void **)opts, free);
-       return fret;
-}
-
-static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
-                                       const struct lxc_rootfs *rootfs,
-                                       const char *lxc_name,
-                                       const char *lxc_path)
-{
-       char lxcpath[MAXPATHLEN];
-       char *rootfsdir = NULL;
-       char *scratch = NULL;
-       char *tmp = NULL;
-       char *upperdir = NULL;
-       char **opts = NULL;
-       int fret = -1;
-       int ret = 0;
-       size_t arrlen = 0;
-       size_t i;
-       size_t len = 0;
-       size_t rootfslen = 0;
-
-       if (!rootfs->path || !lxc_name || !lxc_path)
-               goto err;
-
-       opts = lxc_string_split(mntent->mnt_opts, ',');
-       if (opts)
-               arrlen = lxc_array_len((void **)opts);
-       else
-               goto err;
-
-       for (i = 0; i < arrlen; i++) {
-               if (strstr(opts[i], "br=") && (strlen(opts[i]) > (len = strlen("br="))))
-                       tmp = opts[i] + len;
-       }
-       if (!tmp)
-               goto err;
-
-       upperdir = strtok_r(tmp, ":=", &scratch);
-       if (!upperdir)
-               goto err;
-
-       ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               goto err;
-
-       rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen);
-       if (!rootfsdir)
-               goto err;
-
-       /* We neither allow users to create upperdirs outside the containerdir
-        * nor inside the rootfs. The latter might be debatable. */
-       if ((strncmp(upperdir, lxcpath, strlen(lxcpath)) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
-               if (mkdir_p(upperdir, 0755) < 0) {
-                       WARN("Failed to create upperdir");
-               }
-
-       fret = 0;
-
-err:
-       free(rootfsdir);
-       lxc_free_array((void **)opts, free);
-       return fret;
-}
-
-
 static int mount_entry_create_dir_file(const struct mntent *mntent,
                                       const char* path, const struct lxc_rootfs *rootfs,
                                       const char *lxc_name, const char *lxc_path)
@@ -1987,10 +1743,10 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
        FILE *pathfile = NULL;
 
        if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
-               if (mount_entry_create_overlay_dirs(mntent, rootfs, lxc_name, lxc_path) < 0)
+               if (ovl_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
                        return -1;
        } else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) {
-               if (mount_entry_create_aufs_dirs(mntent, rootfs, lxc_name, lxc_path) < 0)
+               if (aufs_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
                        return -1;
        }
 
@@ -2019,6 +1775,8 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
        return ret;
 }
 
+/* rootfs, lxc_name, and lxc_path can be NULL when the container is created
+ * without a rootfs. */
 static inline int mount_entry_on_generic(struct mntent *mntent,
                  const char* path, const struct lxc_rootfs *rootfs,
                 const char *lxc_name, const char *lxc_path)
@@ -2028,6 +1786,10 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
        int ret;
        bool optional = hasmntopt(mntent, "optional") != NULL;
 
+       char *rootfs_path = NULL;
+       if (rootfs && rootfs->path)
+               rootfs_path = rootfs->mount;
+
        ret = mount_entry_create_dir_file(mntent, path, rootfs, lxc_name, lxc_path);
 
        if (ret < 0)
@@ -2041,8 +1803,7 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
        }
 
        ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
-                         mntdata, optional,
-                         rootfs->path ? rootfs->mount : NULL);
+                         mntdata, optional, rootfs_path);
 
        free(mntdata);
        return ret;
@@ -2050,7 +1811,22 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
 
 static inline int mount_entry_on_systemfs(struct mntent *mntent)
 {
-  return mount_entry_on_generic(mntent, mntent->mnt_dir, NULL, NULL, NULL);
+       char path[MAXPATHLEN];
+       int ret;
+
+       /* For containers created without a rootfs all mounts are treated as
+        * absolute paths starting at / on the host. */
+       if (mntent->mnt_dir[0] != '/')
+               ret = snprintf(path, sizeof(path), "/%s", mntent->mnt_dir);
+       else
+               ret = snprintf(path, sizeof(path), "%s", mntent->mnt_dir);
+
+       if (ret < 0 || ret >= sizeof(path)) {
+               ERROR("path name too long");
+               return -1;
+       }
+
+       return mount_entry_on_generic(mntent, path, NULL, NULL, NULL);
 }
 
 static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
@@ -2111,7 +1887,7 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
 
        /* relative to root mount point */
        ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir);
-       if (ret >= sizeof(path)) {
+       if (ret < 0 || ret >= sizeof(path)) {
                ERROR("path name too long");
                return -1;
        }
@@ -2623,6 +2399,7 @@ void restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
 {
        int i, ret, oldfd;
        char path[MAXPATHLEN];
+       char ifname[IFNAMSIZ];
 
        if (netnsfd < 0)
                return;
@@ -2643,9 +2420,13 @@ void restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
        }
        for (i=0; i<conf->num_savednics; i++) {
                struct saved_nic *s = &conf->saved_nics[i];
-               if (lxc_netdev_move_by_index(s->ifindex, 1, NULL))
-                       WARN("Error moving nic index:%d back to host netns",
-                                       s->ifindex);
+               /* retrieve the name of the interface */
+               if (!if_indextoname(s->ifindex, ifname)) {
+                       WARN("no interface corresponding to index '%d'", s->ifindex);
+                       continue;
+               }
+               if (lxc_netdev_move_by_name(ifname, 1, NULL))
+                       WARN("Error moving nic name:%s back to host netns", ifname);
        }
        if (setns(oldfd, 0) != 0)
                SYSERROR("Failed to re-enter monitor's netns");
@@ -2726,6 +2507,11 @@ struct lxc_conf *lxc_conf_init(void)
        for (i = 0; i < LXC_NS_MAX; i++)
                new->inherit_ns_fd[i] = -1;
 
+       /* if running in a new user namespace, init and COMMAND
+        * default to running as UID/GID 0 when using lxc-execute */
+       new->init_uid = 0;
+       new->init_gid = 0;
+
        return new;
 }
 
@@ -2733,7 +2519,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 {
        char veth1buf[IFNAMSIZ], *veth1;
        char veth2buf[IFNAMSIZ], *veth2;
-       int err;
+       int err, mtu = 0;
 
        if (netdev->priv.veth_attr.pair) {
                veth1 = netdev->priv.veth_attr.pair;
@@ -2778,19 +2564,31 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                goto out_delete;
        }
 
+       netdev->ifindex = if_nametoindex(veth2);
+       if (!netdev->ifindex) {
+               ERROR("failed to retrieve the index for %s", veth2);
+               goto out_delete;
+       }
+
        if (netdev->mtu) {
-               err = lxc_netdev_set_mtu(veth1, atoi(netdev->mtu));
+               mtu = atoi(netdev->mtu);
+       } else if (netdev->link) {
+               mtu = netdev_get_mtu(netdev->ifindex);
+       }
+
+       if (mtu) {
+               err = lxc_netdev_set_mtu(veth1, mtu);
                if (!err)
-                       err = lxc_netdev_set_mtu(veth2, atoi(netdev->mtu));
+                       err = lxc_netdev_set_mtu(veth2, mtu);
                if (err) {
-                       ERROR("failed to set mtu '%s' for veth pair (%s and %s): %s",
-                             netdev->mtu, veth1, veth2, strerror(-err));
+                       ERROR("failed to set mtu '%i' for veth pair (%s and %s): %s",
+                             mtu, veth1, veth2, strerror(-err));
                        goto out_delete;
                }
        }
 
        if (netdev->link) {
-               err = lxc_bridge_attach(netdev->link, veth1);
+               err = lxc_bridge_attach(handler->lxcpath, handler->name, netdev->link, veth1);
                if (err) {
                        ERROR("failed to attach '%s' to the bridge '%s': %s",
                                      veth1, netdev->link, strerror(-err));
@@ -2798,12 +2596,6 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                }
        }
 
-       netdev->ifindex = if_nametoindex(veth2);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for %s", veth2);
-               goto out_delete;
-       }
-
        err = lxc_netdev_up(veth1);
        if (err) {
                ERROR("failed to set %s up : %s", veth1, strerror(-err));
@@ -3111,7 +2903,9 @@ void lxc_delete_network(struct lxc_handler *handler)
                 */
                if (netdev->ifindex != 0 &&
                    lxc_netdev_delete_by_index(netdev->ifindex))
-                       WARN("failed to remove interface '%s'", netdev->name);
+                       WARN("failed to remove interface %d '%s'",
+                               netdev->ifindex,
+                               netdev->name ? netdev->name : "(null)");
        }
 }
 
@@ -3119,12 +2913,14 @@ void lxc_delete_network(struct lxc_handler *handler)
 
 /* lxc-user-nic returns "interface_name:interface_name\n" */
 #define MAX_BUFFER_SIZE IFNAMSIZ*2 + 2
-static int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
+static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
+                            struct lxc_netdev *netdev, pid_t pid)
 {
        pid_t child;
        int bytes, pipefd[2];
        char *token, *saveptr = NULL;
        char buffer[MAX_BUFFER_SIZE];
+       char netdev_link[IFNAMSIZ+1];
 
        if (netdev->type != LXC_NET_VETH) {
                ERROR("nic type %d not support for unprivileged use",
@@ -3154,10 +2950,15 @@ static int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
 
                // Call lxc-user-nic pid type bridge
                char pidstr[20];
-               char *args[] = {LXC_USERNIC_PATH, pidstr, "veth", netdev->link, netdev->name, NULL };
+               if (netdev->link) {
+                       strncpy(netdev_link, netdev->link, IFNAMSIZ);
+               } else {
+                       strncpy(netdev_link, "none", IFNAMSIZ);
+               }
                snprintf(pidstr, 19, "%lu", (unsigned long) pid);
                pidstr[19] = '\0';
-               execvp(args[0], args);
+               execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, lxcpath, lxcname,
+                               pidstr, "veth", netdev_link, netdev->name, NULL);
                SYSERROR("execvp lxc-user-nic");
                exit(1);
        }
@@ -3204,10 +3005,12 @@ static int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
        return 0;
 }
 
-int lxc_assign_network(struct lxc_list *network, pid_t pid)
+int lxc_assign_network(const char *lxcpath, char *lxcname,
+                      struct lxc_list *network, pid_t pid)
 {
        struct lxc_list *iterator;
        struct lxc_netdev *netdev;
+       char ifname[IFNAMSIZ];
        int am_root = (getuid() == 0);
        int err;
 
@@ -3216,7 +3019,7 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
                netdev = iterator->elem;
 
                if (netdev->type == LXC_NET_VETH && !am_root) {
-                       if (unpriv_assign_nic(netdev, pid))
+                       if (unpriv_assign_nic(lxcpath, lxcname, netdev, pid))
                                return -1;
                        // lxc-user-nic has moved the nic to the new ns.
                        // unpriv_assign_nic() fills in netdev->name.
@@ -3228,7 +3031,13 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
                if (!netdev->ifindex)
                        continue;
 
-               err = lxc_netdev_move_by_index(netdev->ifindex, pid, NULL);
+               /* retrieve the name of the interface */
+               if (!if_indextoname(netdev->ifindex, ifname)) {
+                       ERROR("no interface corresponding to index '%d'", netdev->ifindex);
+                       return -1;
+               }
+
+               err = lxc_netdev_move_by_name(ifname, pid, NULL);
                if (err) {
                        ERROR("failed to move '%s' to the container : %s",
                              netdev->link, strerror(-err));
@@ -3669,6 +3478,7 @@ int ttys_shift_ids(struct lxc_conf *c)
        return 0;
 }
 
+/* NOTE: not to be called from inside the container namespace! */
 int tmp_proc_mount(struct lxc_conf *lxc_conf)
 {
        int mounted;
@@ -3943,11 +3753,13 @@ int lxc_setup(struct lxc_handler *handler)
        }
 
        if (lxc_conf->autodev > 0) {
+               bool mount_console = lxc_conf->console.path && !strcmp(lxc_conf->console.path, "none");
+
                if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
                        ERROR("failed to run autodev hooks for container '%s'.", name);
                        return -1;
                }
-               if (fill_autodev(&lxc_conf->rootfs)) {
+               if (fill_autodev(&lxc_conf->rootfs, mount_console)) {
                        ERROR("failed to populate /dev in the container");
                        return -1;
                }
@@ -4044,10 +3856,14 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
                which = LXCHOOK_AUTODEV;
        else if (strcmp(hook, "start") == 0)
                which = LXCHOOK_START;
+       else if (strcmp(hook, "stop") == 0)
+               which = LXCHOOK_STOP;
        else if (strcmp(hook, "post-stop") == 0)
                which = LXCHOOK_POSTSTOP;
        else if (strcmp(hook, "clone") == 0)
                which = LXCHOOK_CLONE;
+       else if (strcmp(hook, "destroy") == 0)
+               which = LXCHOOK_DESTROY;
        else
                return -1;
        lxc_list_for_each(it, &conf->hooks[which]) {
@@ -4327,9 +4143,9 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->console.log_path);
        free(conf->console.path);
        free(conf->rootfs.mount);
+       free(conf->rootfs.bdev_type);
        free(conf->rootfs.options);
        free(conf->rootfs.path);
-       free(conf->rootfs.pivot);
        free(conf->logfile);
        if (conf->logfd != -1)
                close(conf->logfd);
index c01e1a4..2593ce5 100644 (file)
@@ -100,7 +100,7 @@ struct ifla_vlan {
 };
 
 struct ifla_macvlan {
-       int mode; /* private, vepa, bridge */
+       int mode; /* private, vepa, bridge, passthru */
 };
 
 union netdev_p {
@@ -217,14 +217,16 @@ struct lxc_console {
 /*
  * Defines a structure to store the rootfs location, the
  * optionals pivot_root, rootfs mount paths
- * @rootfs     : a path to the rootfs
- * @pivot_root : a path to a pivot_root location to be used
+ * @path       : the rootfs source (directory or device)
+ * @mount      : where it is mounted
+ * @options    : mount options
+ * @bev_type   : optional backing store type
  */
 struct lxc_rootfs {
        char *path;
        char *mount;
-       char *pivot;
        char *options;
+       char *bdev_type;
 };
 
 /*
@@ -279,7 +281,8 @@ enum {
  */
 enum lxchooks {
        LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
-       LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, NUM_LXC_HOOKS};
+       LXCHOOK_START, LXCHOOK_STOP, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, LXCHOOK_DESTROY,
+       NUM_LXC_HOOKS};
 extern char *lxchook_names[NUM_LXC_HOOKS];
 
 struct saved_nic {
@@ -324,6 +327,7 @@ struct lxc_conf {
        int maincmd_fd;
        int autodev;  // if 1, mount and fill a /dev at start
        int haltsignal; // signal used to halt container
+       int rebootsignal; // signal used to reboot container
        int stopsignal; // signal used to hard stop container
        int kmsg;  // if 1, create /dev/kmsg symlink
        char *rcfile;   // Copy of the top level rcfile we read
@@ -345,6 +349,9 @@ struct lxc_conf {
        struct lxc_list groups;
        int nbd_idx;
 
+       /* unshare the mount namespace in the monitor */
+       int monitor_unshare;
+
        /* set to true when rootfs has been setup */
        bool rootfs_setup;
 
@@ -363,6 +370,14 @@ struct lxc_conf {
 
        /* init command */
        char *init_cmd;
+
+       /* if running in a new user namespace, the UID/GID that init and COMMAND
+        * should run under when using lxc-execute */
+       uid_t init_uid;
+       gid_t init_gid;
+
+       /* indicator if the container will be destroyed on shutdown */
+       int ephemeral;
 };
 
 #ifdef HAVE_TLS
@@ -387,7 +402,8 @@ extern int pin_rootfs(const char *rootfs);
 extern int lxc_requests_empty_network(struct lxc_handler *handler);
 extern int lxc_create_network(struct lxc_handler *handler);
 extern void lxc_delete_network(struct lxc_handler *handler);
-extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
+extern int lxc_assign_network(const char *lxcpath, char *lxcname,
+                             struct lxc_list *networks, pid_t pid);
 extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
 extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
 
index 5337451..7f34164 100644 (file)
@@ -42,6 +42,7 @@
 #include "parse.h"
 #include "config.h"
 #include "confile.h"
+#include "bdev/bdev.h"
 #include "utils.h"
 #include "log.h"
 #include "conf.h"
@@ -72,6 +73,7 @@ static int config_fstab(const char *, const char *, struct lxc_conf *);
 static int config_rootfs(const char *, const char *, struct lxc_conf *);
 static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
 static int config_rootfs_options(const char *, const char *, struct lxc_conf *);
+static int config_rootfs_backend(const char *, const char *, struct lxc_conf *);
 static int config_pivotdir(const char *, const char *, struct lxc_conf *);
 static int config_utsname(const char *, const char *, struct lxc_conf *);
 static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf);
@@ -100,11 +102,16 @@ static int config_includefile(const char *, const char *, struct lxc_conf *);
 static int config_network_nic(const char *, const char *, struct lxc_conf *);
 static int config_autodev(const char *, const char *, struct lxc_conf *);
 static int config_haltsignal(const char *, const char *, struct lxc_conf *);
+static int config_rebootsignal(const char *, const char *, struct lxc_conf *);
 static int config_stopsignal(const char *, const char *, struct lxc_conf *);
 static int config_start(const char *, const char *, struct lxc_conf *);
+static int config_monitor(const char *, const char *, struct lxc_conf *);
 static int config_group(const char *, const char *, struct lxc_conf *);
 static int config_environment(const char *, const char *, struct lxc_conf *);
 static int config_init_cmd(const char *, const char *, struct lxc_conf *);
+static int config_init_uid(const char *, const char *, struct lxc_conf *);
+static int config_init_gid(const char *, const char *, struct lxc_conf *);
+static int config_ephemeral(const char *, const char *, struct lxc_conf *);
 
 static struct lxc_config_t config[] = {
 
@@ -125,6 +132,7 @@ static struct lxc_config_t config[] = {
        { "lxc.mount",                config_fstab                },
        { "lxc.rootfs.mount",         config_rootfs_mount         },
        { "lxc.rootfs.options",       config_rootfs_options       },
+       { "lxc.rootfs.backend",       config_rootfs_backend       },
        { "lxc.rootfs",               config_rootfs               },
        { "lxc.pivotdir",             config_pivotdir             },
        { "lxc.utsname",              config_utsname              },
@@ -133,8 +141,10 @@ static struct lxc_config_t config[] = {
        { "lxc.hook.mount",           config_hook                 },
        { "lxc.hook.autodev",         config_hook                 },
        { "lxc.hook.start",           config_hook                 },
+       { "lxc.hook.stop",            config_hook                 },
        { "lxc.hook.post-stop",       config_hook                 },
        { "lxc.hook.clone",           config_hook                 },
+       { "lxc.hook.destroy",         config_hook                 },
        { "lxc.hook",                 config_hook                 },
        { "lxc.network.type",         config_network_type         },
        { "lxc.network.flags",        config_network_flags        },
@@ -162,13 +172,18 @@ static struct lxc_config_t config[] = {
        { "lxc.include",              config_includefile          },
        { "lxc.autodev",              config_autodev              },
        { "lxc.haltsignal",           config_haltsignal           },
+       { "lxc.rebootsignal",         config_rebootsignal         },
        { "lxc.stopsignal",           config_stopsignal           },
        { "lxc.start.auto",           config_start                },
        { "lxc.start.delay",          config_start                },
        { "lxc.start.order",          config_start                },
+       { "lxc.monitor.unshare",      config_monitor              },
        { "lxc.group",                config_group                },
        { "lxc.environment",          config_environment          },
        { "lxc.init_cmd",             config_init_cmd             },
+       { "lxc.init_uid",             config_init_uid             },
+       { "lxc.init_gid",             config_init_gid             },
+       { "lxc.ephemeral",            config_ephemeral            },
 };
 
 struct signame {
@@ -576,6 +591,10 @@ static int network_ifname(char **valuep, const char *value)
 #  define MACVLAN_MODE_BRIDGE 4
 #endif
 
+#ifndef MACVLAN_MODE_PASSTHRU
+#  define MACVLAN_MODE_PASSTHRU 8
+#endif
+
 static int macvlan_mode(int *valuep, const char *value)
 {
        struct mc_mode {
@@ -585,6 +604,7 @@ static int macvlan_mode(int *valuep, const char *value)
                { "private", MACVLAN_MODE_PRIVATE },
                { "vepa", MACVLAN_MODE_VEPA },
                { "bridge", MACVLAN_MODE_BRIDGE },
+               { "passthru", MACVLAN_MODE_PASSTHRU },
        };
 
        int i;
@@ -954,7 +974,7 @@ static int config_network_ipv6_gateway(const char *key, const char *value,
        free(netdev->ipv6_gateway);
 
        if (!value || strlen(value) == 0) {
-               netdev->ipv4_gateway = NULL;
+               netdev->ipv6_gateway = NULL;
        } else if (!strcmp(value, "auto")) {
                netdev->ipv6_gateway = NULL;
                netdev->ipv6_gateway_auto = true;
@@ -1030,11 +1050,25 @@ static int config_init_cmd(const char *key, const char *value,
        return config_path_item(&lxc_conf->init_cmd, value);
 }
 
+static int config_init_uid(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       lxc_conf->init_uid = atoi(value);
+       return 0;
+}
+
+static int config_init_gid(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       lxc_conf->init_gid = atoi(value);
+       return 0;
+}
+
 static int config_hook(const char *key, const char *value,
                                 struct lxc_conf *lxc_conf)
 {
        char *copy;
-       
+
        if (!value || strlen(value) == 0)
                return lxc_clear_hooks(lxc_conf, key);
 
@@ -1057,10 +1091,14 @@ static int config_hook(const char *key, const char *value,
                return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
        else if (strcmp(key, "lxc.hook.start") == 0)
                return add_hook(lxc_conf, LXCHOOK_START, copy);
+       else if (strcmp(key, "lxc.hook.stop") == 0)
+               return add_hook(lxc_conf, LXCHOOK_STOP, copy);
        else if (strcmp(key, "lxc.hook.post-stop") == 0)
                return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
        else if (strcmp(key, "lxc.hook.clone") == 0)
                return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
+       else if (strcmp(key, "lxc.hook.destroy") == 0)
+               return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
        SYSERROR("Unknown key: %s", key);
        free(copy);
        return -1;
@@ -1108,6 +1146,17 @@ static int config_start(const char *key, const char *value,
        return -1;
 }
 
+static int config_monitor(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
+{
+       if(strcmp(key, "lxc.monitor.unshare") == 0) {
+               lxc_conf->monitor_unshare = atoi(value);
+               return 0;
+       }
+       SYSERROR("Unknown key: %s", key);
+       return -1;
+}
+
 static int config_group(const char *key, const char *value,
                      struct lxc_conf *lxc_conf)
 {
@@ -1329,6 +1378,18 @@ static int config_haltsignal(const char *key, const char *value,
        return 0;
 }
 
+static int config_rebootsignal(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
+{
+       int sig_n = sig_parse(value);
+
+       if (sig_n < 0)
+               return -1;
+       lxc_conf->rebootsignal = sig_n;
+
+       return 0;
+}
+
 static int config_stopsignal(const char *key, const char *value,
                          struct lxc_conf *lxc_conf)
 {
@@ -1795,11 +1856,26 @@ static int config_rootfs_options(const char *key, const char *value,
        return config_string_item(&lxc_conf->rootfs.options, value);
 }
 
+static int config_rootfs_backend(const char *key, const char *value,
+                              struct lxc_conf *lxc_conf)
+{
+       if (strlen(value) == 0) {
+               free(lxc_conf->rootfs.bdev_type);
+               lxc_conf->rootfs.bdev_type = NULL;
+       }
+       if (!is_valid_bdev_type(value)) {
+               ERROR("Bad rootfs.backend: '%s'", value);
+               return -1;
+       }
+
+       return config_string_item(&lxc_conf->rootfs.bdev_type, value);
+}
+
 static int config_pivotdir(const char *key, const char *value,
                           struct lxc_conf *lxc_conf)
 {
        WARN("lxc.pivotdir is ignored.  It will soon become an error.");
-       return config_path_item(&lxc_conf->rootfs.pivot, value);
+       return 0;
 }
 
 static int config_utsname(const char *key, const char *value,
@@ -2305,6 +2381,7 @@ static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
                        case MACVLAN_MODE_PRIVATE: mode = "private"; break;
                        case MACVLAN_MODE_VEPA: mode = "vepa"; break;
                        case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
+                       case MACVLAN_MODE_PASSTHRU: mode = "passthru"; break;
                        default: mode = "(invalid)"; break;
                        }
                        strprint(retv, inlen, "%s", mode);
@@ -2415,12 +2492,12 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
                v = c->console.path;
        else if (strcmp(key, "lxc.rootfs.mount") == 0)
                v = c->rootfs.mount;
+       else if (strcmp(key, "lxc.rootfs.backend") == 0)
+               v = c->rootfs.bdev_type;
        else if (strcmp(key, "lxc.rootfs.options") == 0)
                v = c->rootfs.options;
        else if (strcmp(key, "lxc.rootfs") == 0)
                v = c->rootfs.path;
-       else if (strcmp(key, "lxc.pivotdir") == 0)
-               v = c->rootfs.pivot;
        else if (strcmp(key, "lxc.cap.drop") == 0)
                return lxc_get_item_cap_drop(c, retv, inlen);
        else if (strcmp(key, "lxc.cap.keep") == 0)
@@ -2437,6 +2514,8 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
                return lxc_get_conf_int(c, retv, inlen, c->start_delay);
        else if (strcmp(key, "lxc.start.order") == 0)
                return lxc_get_conf_int(c, retv, inlen, c->start_order);
+       else if (strcmp(key, "lxc.monitor.unshare") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
        else if (strcmp(key, "lxc.group") == 0)
                return lxc_get_item_groups(c, retv, inlen);
        else if (strcmp(key, "lxc.seccomp") == 0)
@@ -2445,6 +2524,12 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
                return lxc_get_item_environment(c, retv, inlen);
        else if (strcmp(key, "lxc.init_cmd") == 0)
                v = c->init_cmd;
+       else if (strcmp(key, "lxc.init_uid") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->init_uid);
+       else if (strcmp(key, "lxc.init_gid") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->init_gid);
+       else if (strcmp(key, "lxc.ephemeral") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
        else return -1;
 
        if (!v)
@@ -2466,7 +2551,7 @@ int lxc_clear_config_item(struct lxc_conf *c, const char *key)
                return lxc_clear_config_keepcaps(c);
        else if (strncmp(key, "lxc.cgroup", 10) == 0)
                return lxc_clear_cgroups(c, key);
-       else if (strcmp(key, "lxc.mount.entries") == 0)
+       else if (strcmp(key, "lxc.mount.entry") == 0)
                return lxc_clear_mount_entries(c);
        else if (strcmp(key, "lxc.mount.auto") == 0)
                return lxc_clear_automounts(c);
@@ -2808,3 +2893,19 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
        }
        return true;
 }
+
+static int config_ephemeral(const char *key, const char *value,
+                           struct lxc_conf *lxc_conf)
+{
+       int v = atoi(value);
+
+       if (v != 0 && v != 1) {
+               ERROR("Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
+               return -1;
+       } else {
+               lxc_conf->ephemeral = v;
+       }
+
+       return 0;
+}
+
index 67e5d0f..5df73e4 100644 (file)
  */
 
 #include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <sys/epoll.h>
 #include <sys/types.h>
 #include <termios.h>
+#include <unistd.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "log.h"
-#include "conf.h"
-#include "config.h"
-#include "start.h"     /* for struct lxc_handler */
+#include "af_unix.h"
 #include "caps.h"
 #include "commands.h"
-#include "mainloop.h"
-#include "af_unix.h"
+#include "conf.h"
+#include "config.h"
+#include "console.h"
+#include "log.h"
 #include "lxclock.h"
+#include "mainloop.h"
+#include "start.h"     /* for struct lxc_handler */
 #include "utils.h"
 
 #if HAVE_PTY_H
@@ -55,19 +57,6 @@ lxc_log_define(lxc_console, lxc);
 static struct lxc_list lxc_ttys;
 
 typedef void (*sighandler_t)(int);
-struct lxc_tty_state
-{
-       struct lxc_list node;
-       int stdinfd;
-       int stdoutfd;
-       int masterfd;
-       int escape;
-       int saw_escape;
-       const char *winch_proxy;
-       const char *winch_proxy_lxcpath;
-       int sigfd;
-       sigset_t oldmask;
-};
 
 __attribute__((constructor))
 void lxc_console_init(void)
@@ -75,12 +64,7 @@ void lxc_console_init(void)
        lxc_list_init(&lxc_ttys);
 }
 
-/* lxc_console_winsz: propagte winsz from one terminal to another
- *
- * @srcfd : terminal to get size from (typically a slave pty)
- * @dstfd : terminal to set size on (typically a master pty)
- */
-static void lxc_console_winsz(int srcfd, int dstfd)
+void lxc_console_winsz(int srcfd, int dstfd)
 {
        struct winsize wsz;
        if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
@@ -93,10 +77,8 @@ static void lxc_console_winsz(int srcfd, int dstfd)
 static void lxc_console_winch(struct lxc_tty_state *ts)
 {
        lxc_console_winsz(ts->stdinfd, ts->masterfd);
-       if (ts->winch_proxy) {
-               lxc_cmd_console_winch(ts->winch_proxy,
-                                     ts->winch_proxy_lxcpath);
-       }
+       if (ts->winch_proxy)
+               lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
 }
 
 void lxc_console_sigwinch(int sig)
@@ -110,13 +92,14 @@ void lxc_console_sigwinch(int sig)
        }
 }
 
-static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
-                                     struct lxc_epoll_descr *descr)
+int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr)
 {
        struct signalfd_siginfo siginfo;
        struct lxc_tty_state *ts = cbdata;
 
-       if (read(fd, &siginfo, sizeof(siginfo)) < sizeof(siginfo)) {
+       ssize_t ret = read(fd, &siginfo, sizeof(siginfo));
+       if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
                ERROR("failed to read signal info");
                return -1;
        }
@@ -125,27 +108,7 @@ static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
        return 0;
 }
 
-/*
- * lxc_console_sigwinch_init: install SIGWINCH handler
- *
- * @srcfd  : src for winsz in SIGWINCH handler
- * @dstfd  : dst for winsz in SIGWINCH handler
- *
- * Returns lxc_tty_state structure on success or NULL on failure. The sigfd
- * member of the returned lxc_tty_state can be select()/poll()ed/epoll()ed
- * on (ie added to a mainloop) for SIGWINCH.
- *
- * Must be called with process_lock held to protect the lxc_ttys list, or
- * from a non-threaded context.
- *
- * Note that SIGWINCH isn't installed as a classic asychronous handler,
- * rather signalfd(2) is used so that we can handle the signal when we're
- * ready for it. This avoids deadlocks since a signal handler
- * (ie lxc_console_sigwinch()) would need to take the thread mutex to
- * prevent lxc_ttys list corruption, but using the fd we can provide the
- * tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
- */
-static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
+struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 {
        sigset_t mask;
        struct lxc_tty_state *ts;
@@ -189,22 +152,11 @@ out:
        return ts;
 }
 
-/*
- * lxc_console_sigwinch_fini: uninstall SIGWINCH handler
- *
- * @ts  : the lxc_tty_state returned by lxc_console_sigwinch_init
- *
- * Restore the saved signal handler that was in effect at the time
- * lxc_console_sigwinch_init() was called.
- *
- * Must be called with process_lock held to protect the lxc_ttys list, or
- * from a non-threaded context.
- */
-static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
+void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
 {
-       if (ts->sigfd >= 0) {
+       if (ts->sigfd >= 0)
                close(ts->sigfd);
-       }
+
        lxc_list_del(&ts->node);
        sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
        free(ts);
@@ -243,6 +195,7 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
 
        if (w != r)
                WARN("console short write r:%d w:%d", r, w);
+
        return 0;
 }
 
@@ -302,7 +255,7 @@ int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
        return 0;
 }
 
-static int setup_tios(int fd, struct termios *oldtios)
+int lxc_setup_tios(int fd, struct termios *oldtios)
 {
        struct termios newtios;
 
@@ -382,7 +335,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
                return -1;
        }
 
-       if (setup_tios(console->peerpty.slave, &oldtermio) < 0)
+       if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
                goto err1;
 
        ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
@@ -402,13 +355,6 @@ err1:
        return -1;
 }
 
-/* lxc_console_allocate: allocate the console or a tty
- *
- * @conf    : the configuration of the container to allocate from
- * @sockfd  : the socket fd whose remote side when closed, will be an
- *            indication that the console or tty is no longer in use
- * @ttyreq  : the tty requested to be opened, -1 for any, 0 for the console
- */
 int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
 {
        int masterfd = -1, ttynum;
@@ -435,9 +381,8 @@ int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
        }
 
        /* search for next available tty, fixup index tty1 => [0] */
-       for (ttynum = 1;
-            ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
-            ttynum++);
+       for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
+               ;
 
        /* we didn't find any available slot for tty */
        if (ttynum > tty_info->nbtty)
@@ -452,14 +397,6 @@ out:
        return masterfd;
 }
 
-/* lxc_console_free: mark the console or a tty as unallocated, free any
- * resources allocated by lxc_console_allocate().
- *
- * @conf : the configuration of the container whose tty was closed
- * @fd   : the socket fd whose remote side was closed, which indicated
- *         the console or tty is no longer in use. this is used to match
- *         which console/tty is being freed.
- */
 void lxc_console_free(struct lxc_conf *conf, int fd)
 {
        int i;
@@ -521,7 +458,7 @@ static void lxc_console_peer_default(struct lxc_console *console)
                goto err1;
        }
 
-       if (setup_tios(console->peer, console->tios) < 0)
+       if (lxc_setup_tios(console->peer, console->tios) < 0)
                goto err2;
 
        return;
@@ -611,46 +548,60 @@ err:
        return -1;
 }
 
-int lxc_console_set_stdfds(struct lxc_handler *handler)
+int lxc_console_set_stdfds(int fd)
 {
-       struct lxc_conf *conf = handler->conf;
-       struct lxc_console *console = &conf->console;
-
-       if (console->slave < 0)
+       if (fd < 0)
                return 0;
 
-       if (dup2(console->slave, 0) < 0 ||
-           dup2(console->slave, 1) < 0 ||
-           dup2(console->slave, 2) < 0)
-       {
-               SYSERROR("failed to dup console");
-               return -1;
-       }
+       if (isatty(STDIN_FILENO))
+               if (dup2(fd, STDIN_FILENO) < 0) {
+                       SYSERROR("failed to duplicate stdin.");
+                       return -1;
+               }
+
+       if (isatty(STDOUT_FILENO))
+               if (dup2(fd, STDOUT_FILENO) < 0) {
+                       SYSERROR("failed to duplicate stdout.");
+                       return -1;
+               }
+
+       if (isatty(STDERR_FILENO))
+               if (dup2(fd, STDERR_FILENO) < 0) {
+                       SYSERROR("failed to duplicate stderr.");
+                       return -1;
+               }
+
        return 0;
 }
 
-static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
-                                   struct lxc_epoll_descr *descr)
+int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr)
 {
        struct lxc_tty_state *ts = cbdata;
        char c;
 
+       if (events & EPOLLHUP)
+               return 1;
+
        assert(fd == ts->stdinfd);
        if (read(ts->stdinfd, &c, 1) < 0) {
                SYSERROR("failed to read");
                return 1;
        }
 
-       /* we want to exit the console with Ctrl+a q */
-       if (c == ts->escape && !ts->saw_escape) {
-               ts->saw_escape = 1;
-               return 0;
-       }
+       if (ts->escape != -1) {
+               /* we want to exit the console with Ctrl+a q */
+               if (c == ts->escape && !ts->saw_escape) {
+                       ts->saw_escape = 1;
+                       return 0;
+               }
 
-       if (c == 'q' && ts->saw_escape)
-               return 1;
+               if (c == 'q' && ts->saw_escape)
+                       return 1;
+
+               ts->saw_escape = 0;
+       }
 
-       ts->saw_escape = 0;
        if (write(ts->masterfd, &c, 1) < 0) {
                SYSERROR("failed to write");
                return 1;
@@ -659,12 +610,15 @@ static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
        return 0;
 }
 
-static int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
-                                    struct lxc_epoll_descr *descr)
+int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr)
 {
        struct lxc_tty_state *ts = cbdata;
        char buf[1024];
-       int r,w;
+       int r, w;
+
+       if (events & EPOLLHUP)
+               return 1;
 
        assert(fd == ts->masterfd);
        r = read(fd, buf, sizeof(buf));
@@ -701,7 +655,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
                return -1;
        }
 
-       ret = setup_tios(stdinfd, &oldtios);
+       ret = lxc_setup_tios(stdinfd, &oldtios);
        if (ret) {
                ERROR("failed to setup tios");
                return -1;
@@ -782,3 +736,4 @@ err1:
 
        return ret;
 }
+
index 41d53e6..1f0a070 100644 (file)
 #ifndef __LXC_CONSOLE_H
 #define __LXC_CONSOLE_H
 
-struct lxc_epoll_descr;
-struct lxc_container;
+#include "conf.h"
+#include "list.h"
 
+struct lxc_epoll_descr; /* defined in mainloop.h */
+struct lxc_container; /* defined in lxccontainer.h */
+struct lxc_tty_state
+{
+       struct lxc_list node;
+       int stdinfd;
+       int stdoutfd;
+       int masterfd;
+       /* Escape sequence to use for exiting the pty. A single char can be
+        * specified. The pty can then exited by doing: Ctrl + specified_char + q.
+        * This field is checked by lxc_console_cb_tty_stdin(). Set to -1 to
+        * disable exiting the pty via a escape sequence. */
+       int escape;
+       /* Used internally by lxc_console_cb_tty_stdin() to check whether an
+        * escape sequence has been received. */
+       int saw_escape;
+       /* Name of the container to forward the SIGWINCH event to. */
+       const char *winch_proxy;
+       /* Path of the container to forward the SIGWINCH event to. */
+       const char *winch_proxy_lxcpath;
+       /* File descriptor that accepts SIGWINCH signals. */
+       int sigfd;
+       sigset_t oldmask;
+};
+
+/*
+ * lxc_console_allocate: allocate the console or a tty
+ *
+ * @conf    : the configuration of the container to allocate from
+ * @sockfd  : the socket fd whose remote side when closed, will be an
+ *            indication that the console or tty is no longer in use
+ * @ttyreq  : the tty requested to be opened, -1 for any, 0 for the console
+ */
 extern int  lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
+
+/*
+ * Create a new pty:
+ * - calls openpty() to allocate a master/slave pty pair
+ * - sets the FD_CLOEXEC flag on the master/slave fds
+ * - allocates either the current controlling pty (default) or a user specified
+ *   pty as peer pty for the newly created master/slave pair
+ * - sets up SIGWINCH handler, winsz, and new terminal settings
+ *   (Handlers for SIGWINCH and I/O are not registered in a mainloop.)
+ * (For an unprivileged container the created pty on the host is not
+ * automatically chowned to the uid/gid of the unprivileged user. For this
+ * ttys_shift_ids() can be called.)
+ */
 extern int  lxc_console_create(struct lxc_conf *);
+
+/*
+ * Delete a pty created via lxc_console_create():
+ * - set old terminal settings
+ * - memory allocated via lxc_console_create() is free()ed.
+ * - close master/slave pty pair and allocated fd for the peer (usually
+ *   /dev/tty)
+ * Registered handlers in a mainloop are not automatically deleted.
+ */
 extern void lxc_console_delete(struct lxc_console *);
+
+/*
+ * lxc_console_free: mark the console or a tty as unallocated, free any
+ * resources allocated by lxc_console_allocate().
+ *
+ * @conf : the configuration of the container whose tty was closed
+ * @fd   : the socket fd whose remote side was closed, which indicated
+ *         the console or tty is no longer in use. this is used to match
+ *         which console/tty is being freed.
+ */
 extern void lxc_console_free(struct lxc_conf *conf, int fd);
 
+/*
+ * Register pty event handlers in an open mainloop
+ */
 extern int  lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
+
+/*
+ * Handle SIGWINCH events on the allocated ptys.
+ */
 extern void lxc_console_sigwinch(int sig);
+
+/*
+ * Connect to one of the ptys given to the container via lxc.tty.
+ * - allocates either the current controlling pty (default) or a user specified
+ *   pty as peer pty for the containers tty
+ * - sets up SIGWINCH handler, winsz, and new terminal settings
+ * - opens mainloop
+ * - registers SIGWINCH, I/O handlers in the mainloop
+ * - performs all necessary cleanup operations
+ */
 extern int  lxc_console(struct lxc_container *c, int ttynum,
                        int stdinfd, int stdoutfd, int stderrfd,
                        int escape);
+
+/*
+ * Allocate one of the ptys given to the container via lxc.tty. Returns an open
+ * fd to the allocated pty.
+ * Set ttynum to -1 to allocate the first available pty, or to a value within
+ * the range specified by lxc.tty to allocate a specific pty.
+ */
 extern int  lxc_console_getfd(struct lxc_container *c, int *ttynum,
                              int *masterfd);
-extern int  lxc_console_set_stdfds(struct lxc_handler *);
+
+/*
+ * Make fd a duplicate of the standard file descriptors:
+ * fd is made a duplicate of a specific standard file descriptor iff the
+ * standard file descriptor refers to a pty.
+ */
+extern int lxc_console_set_stdfds(int fd);
+
+/*
+ * Handler for events on the stdin fd of the pty. To be registered via the
+ * corresponding functions declared and defined in mainloop.{c,h} or
+ * lxc_console_mainloop_add().
+ * This function exits the loop cleanly when an EPOLLHUP event is received.
+ */
+extern int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr);
+
+/*
+ * Handler for events on the master fd of the pty. To be registered via the
+ * corresponding functions declared and defined in mainloop.{c,h} or
+ * lxc_console_mainloop_add().
+ * This function exits the loop cleanly when an EPOLLHUP event is received.
+ */
+extern int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr);
+
+/*
+ * Setup new terminal properties. The old terminal settings are stored in
+ * oldtios.
+ */
+extern int lxc_setup_tios(int fd, struct termios *oldtios);
+
+
+/*
+ * lxc_console_winsz: propagte winsz from one terminal to another
+ *
+ * @srcfd : terminal to get size from (typically a slave pty)
+ * @dstfd : terminal to set size on (typically a master pty)
+ */
+extern void lxc_console_winsz(int srcfd, int dstfd);
+
+/*
+ * lxc_console_sigwinch_init: install SIGWINCH handler
+ *
+ * @srcfd  : src for winsz in SIGWINCH handler
+ * @dstfd  : dst for winsz in SIGWINCH handler
+ *
+ * Returns lxc_tty_state structure on success or NULL on failure. The sigfd
+ * member of the returned lxc_tty_state can be select()/poll()ed/epoll()ed
+ * on (ie added to a mainloop) for SIGWINCH.
+ *
+ * Must be called with process_lock held to protect the lxc_ttys list, or
+ * from a non-threaded context.
+ *
+ * Note that SIGWINCH isn't installed as a classic asychronous handler,
+ * rather signalfd(2) is used so that we can handle the signal when we're
+ * ready for it. This avoids deadlocks since a signal handler
+ * (ie lxc_console_sigwinch()) would need to take the thread mutex to
+ * prevent lxc_ttys list corruption, but using the fd we can provide the
+ * tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
+ *
+ * This function allocates memory. It is up to the caller to free it.
+ */
+extern struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd);
+
+/*
+ * Handler for SIGWINCH events. To be registered via the corresponding functions
+ * declared and defined in mainloop.{c,h} or lxc_console_mainloop_add().
+ */
+extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
+               struct lxc_epoll_descr *descr);
+
+/*
+ * lxc_console_sigwinch_fini: uninstall SIGWINCH handler
+ *
+ * @ts  : the lxc_tty_state returned by lxc_console_sigwinch_init
+ *
+ * Restore the saved signal handler that was in effect at the time
+ * lxc_console_sigwinch_init() was called.
+ *
+ * Must be called with process_lock held to protect the lxc_ttys list, or
+ * from a non-threaded context.
+ */
+extern void lxc_console_sigwinch_fini(struct lxc_tty_state *ts);
 
 #endif
index 7ee6cbe..3645bab 100644 (file)
 
 #include "config.h"
 
-#include "bdev.h"
+#include "bdev/bdev.h"
 #include "cgroup.h"
 #include "conf.h"
+#include "commands.h"
 #include "criu.h"
 #include "log.h"
 #include "lxc.h"
 #include "network.h"
 #include "utils.h"
 
+#define CRIU_VERSION           "2.0"
+
+#define CRIU_GITID_VERSION     "2.0"
+#define CRIU_GITID_PATCHLEVEL  0
+
 lxc_log_define(lxc_criu, lxc);
 
-void exec_criu(struct criu_opts *opts)
+struct criu_opts {
+       /* The type of criu invocation, one of "dump" or "restore" */
+       char *action;
+
+       /* The directory to pass to criu */
+       char *directory;
+
+       /* The container to dump */
+       struct lxc_container *c;
+
+       /* Enable criu verbose mode? */
+       bool verbose;
+
+       /* (pre-)dump: a directory for the previous dump's images */
+       char *predump_dir;
+
+       /* dump: stop the container or not after dumping? */
+       bool stop;
+       char tty_id[32]; /* the criu tty id for /dev/console, i.e. "tty[${rdev}:${dev}]" */
+
+       /* restore: the file to write the init process' pid into */
+       char *pidfile;
+       const char *cgroup_path;
+       int console_fd;
+       /* The path that is bind mounted from /dev/console, if any. We don't
+        * want to use `--ext-mount-map auto`'s result here because the pts
+        * device may have a different path (e.g. if the pty number is
+        * different) on the target host. NULL if lxc.console = "none".
+        */
+       char *console_name;
+
+       /* Address and port where a criu pageserver is listening */
+       char *pageserver_address;
+       char *pageserver_port;
+};
+
+static int load_tty_major_minor(char *directory, char *output, int len)
+{
+       FILE *f;
+       char path[PATH_MAX];
+       int ret;
+
+       ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
+       if (ret < 0 || ret >= sizeof(path)) {
+               ERROR("snprintf'd too many chacters: %d", ret);
+               return -1;
+       }
+
+       f = fopen(path, "r");
+       if (!f) {
+               /* This means we're coming from a liblxc which didn't export
+                * the tty info. In this case they had to have lxc.console =
+                * none, so there's no problem restoring.
+                */
+               if (errno == ENOENT)
+                       return 0;
+
+               SYSERROR("couldn't open %s", path);
+               return -1;
+       }
+
+       if (!fgets(output, len, f)) {
+               fclose(f);
+               SYSERROR("couldn't read %s", path);
+               return -1;
+       }
+
+       fclose(f);
+       return 0;
+}
+
+static void exec_criu(struct criu_opts *opts)
 {
        char **argv, log[PATH_MAX];
-       int static_args = 22, argc = 0, i, ret;
+       int static_args = 24, argc = 0, i, ret;
        int netnr = 0;
        struct lxc_list *it;
 
-       char buf[4096];
+       char buf[4096], tty_info[32];
+       size_t pos;
+       /* If we are currently in a cgroup /foo/bar, and the container is in a
+        * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
+        * container has an open fd that points to one of the cgroup files
+        * (systemd always opens its "root" cgroup). So, let's escape to the
+        * /actual/ root cgroup so that lxcfs thinks criu has enough rights to
+        * see all cgroups.
+        */
+       if (!cgroup_escape()) {
+               ERROR("failed to escape cgroups");
+               return;
+       }
 
        /* The command line always looks like:
         * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
         * --manage-cgroups action-script foo.sh -D $(directory) \
         * -o $(directory)/$(action).log --ext-mount-map auto
         * --enable-external-sharing --enable-external-masters
-        * --enable-fs hugetlbfs --enable-fs tracefs
+        * --enable-fs hugetlbfs --enable-fs tracefs --ext-mount-map console:/dev/pts/n
         * +1 for final NULL */
 
-       if (strcmp(opts->action, "dump") == 0) {
-               /* -t pid */
-               static_args += 2;
+       if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) {
+               /* -t pid --freeze-cgroup /lxc/ct */
+               static_args += 4;
 
-               /* --leave-running */
-               if (!opts->stop)
+               /* --prev-images-dir <path-to-directory-A-relative-to-B> */
+               if (opts->predump_dir)
+                       static_args += 2;
+
+               /* --page-server --address <address> --port <port> */
+               if (opts->pageserver_address && opts->pageserver_port)
+                       static_args += 5;
+
+               /* --leave-running (only for final dump) */
+               if (strcmp(opts->action, "dump") == 0 && !opts->stop)
                        static_args++;
+
+               /* --external tty[88,4] */
+               if (opts->tty_id[0])
+                       static_args += 2;
        } else if (strcmp(opts->action, "restore") == 0) {
                /* --root $(lxc_mount_point) --restore-detached
-                * --restore-sibling --pidfile $foo --cgroup-root $foo */
-               static_args += 8;
+                * --restore-sibling --pidfile $foo --cgroup-root $foo
+                * --lsm-profile apparmor:whatever
+                */
+               static_args += 10;
+
+               tty_info[0] = 0;
+               if (load_tty_major_minor(opts->directory, tty_info, sizeof(tty_info)))
+                       return;
+
+               /* --inherit-fd fd[%d]:tty[%s] */
+               if (tty_info[0])
+                       static_args += 2;
        } else {
                return;
        }
@@ -132,19 +243,58 @@ void exec_criu(struct criu_opts *opts)
        if (opts->verbose)
                DECLARE_ARG("-vvvvvv");
 
-       if (strcmp(opts->action, "dump") == 0) {
-               char pid[32];
+       if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) {
+               char pid[32], *freezer_relative;
 
                if (sprintf(pid, "%d", opts->c->init_pid(opts->c)) < 0)
                        goto err;
 
                DECLARE_ARG("-t");
                DECLARE_ARG(pid);
-               if (!opts->stop)
+
+               freezer_relative = lxc_cmd_get_cgroup_path(opts->c->name,
+                                                          opts->c->config_path,
+                                                          "freezer");
+               if (!freezer_relative) {
+                       ERROR("failed getting freezer path");
+                       goto err;
+               }
+
+               ret = snprintf(log, sizeof(log), "/sys/fs/cgroup/freezer/%s", freezer_relative);
+               if (ret < 0 || ret >= sizeof(log))
+                       goto err;
+
+               DECLARE_ARG("--freeze-cgroup");
+               DECLARE_ARG(log);
+
+               if (opts->tty_id[0]) {
+                       DECLARE_ARG("--ext-mount-map");
+                       DECLARE_ARG("/dev/console:console");
+
+                       DECLARE_ARG("--external");
+                       DECLARE_ARG(opts->tty_id);
+               }
+
+               if (opts->predump_dir) {
+                       DECLARE_ARG("--prev-images-dir");
+                       DECLARE_ARG(opts->predump_dir);
+               }
+
+               if (opts->pageserver_address && opts->pageserver_port) {
+                       DECLARE_ARG("--page-server");
+                       DECLARE_ARG("--address");
+                       DECLARE_ARG(opts->pageserver_address);
+                       DECLARE_ARG("--port");
+                       DECLARE_ARG(opts->pageserver_port);
+               }
+
+               /* only for final dump */
+               if (strcmp(opts->action, "dump") == 0 && !opts->stop)
                        DECLARE_ARG("--leave-running");
        } else if (strcmp(opts->action, "restore") == 0) {
                void *m;
                int additional;
+               struct lxc_conf *lxc_conf = opts->c->lxc_conf;
 
                DECLARE_ARG("--root");
                DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
@@ -155,11 +305,46 @@ void exec_criu(struct criu_opts *opts)
                DECLARE_ARG("--cgroup-root");
                DECLARE_ARG(opts->cgroup_path);
 
+               if (tty_info[0]) {
+                       if (opts->console_fd < 0) {
+                               ERROR("lxc.console configured on source host but not target");
+                               goto err;
+                       }
+
+                       ret = snprintf(buf, sizeof(buf), "fd[%d]:%s", opts->console_fd, tty_info);
+                       if (ret < 0 || ret >= sizeof(buf))
+                               goto err;
+
+                       DECLARE_ARG("--inherit-fd");
+                       DECLARE_ARG(buf);
+               }
+               if (opts->console_name) {
+                       if (snprintf(buf, sizeof(buf), "console:%s", opts->console_name) < 0) {
+                               SYSERROR("sprintf'd too many bytes");
+                       }
+                       DECLARE_ARG("--ext-mount-map");
+                       DECLARE_ARG(buf);
+               }
+
+               if (lxc_conf->lsm_aa_profile || lxc_conf->lsm_se_context) {
+
+                       if (lxc_conf->lsm_aa_profile)
+                               ret = snprintf(buf, sizeof(buf), "apparmor:%s", lxc_conf->lsm_aa_profile);
+                       else
+                               ret = snprintf(buf, sizeof(buf), "selinux:%s", lxc_conf->lsm_se_context);
+
+                       if (ret < 0 || ret >= sizeof(buf))
+                               goto err;
+
+                       DECLARE_ARG("--lsm-profile");
+                       DECLARE_ARG(buf);
+               }
+
                additional = lxc_list_len(&opts->c->lxc_conf->network) * 2;
 
-               m = realloc(argv, (argc + additional + 1) * sizeof(*argv));     \
-               if (!m)                                                         \
-                       goto err;                                               \
+               m = realloc(argv, (argc + additional + 1) * sizeof(*argv));
+               if (!m)
+                       goto err;
                argv = m;
 
                lxc_list_for_each(it, &opts->c->lxc_conf->network) {
@@ -193,6 +378,19 @@ void exec_criu(struct criu_opts *opts)
 
        argv[argc] = NULL;
 
+       buf[0] = 0;
+       pos = 0;
+
+       for (i = 0; argv[i]; i++) {
+               ret = snprintf(buf + pos, sizeof(buf) - pos, "%s ", argv[i]);
+               if (ret < 0 || ret >= sizeof(buf) - pos)
+                       goto err;
+               else
+                       pos += ret;
+       }
+
+       INFO("execing: %s", buf);
+
 #undef DECLARE_ARG
        execv(argv[0], argv);
 err:
@@ -259,7 +457,7 @@ static bool criu_version_ok()
                        return false;
                }
 
-               if (fscanf(f, "Version: %1024[^\n]s", version) != 1)
+               if (fscanf(f, "Version: %1023[^\n]s", version) != 1)
                        goto version_error;
 
                if (fgetc(f) != '\n')
@@ -268,7 +466,7 @@ static bool criu_version_ok()
                if (strcmp(version, CRIU_VERSION) >= 0)
                        goto version_match;
 
-               if (fscanf(f, "GitID: v%1024[^-]s", version) != 1)
+               if (fscanf(f, "GitID: v%1023[^-]s", version) != 1)
                        goto version_error;
 
                if (fgetc(f) != '-')
@@ -296,10 +494,9 @@ version_error:
 
 /* Check and make sure the container has a configuration that we know CRIU can
  * dump. */
-bool criu_ok(struct lxc_container *c)
+static bool criu_ok(struct lxc_container *c)
 {
        struct lxc_list *it;
-       bool found_deny_rule = false;
 
        if (!criu_version_ok())
                return false;
@@ -323,33 +520,6 @@ bool criu_ok(struct lxc_container *c)
                }
        }
 
-       // These requirements come from http://criu.org/LXC
-       if (c->lxc_conf->console.path &&
-                       strcmp(c->lxc_conf->console.path, "none") != 0) {
-               ERROR("lxc.console must be none\n");
-               return false;
-       }
-
-       if (c->lxc_conf->tty != 0) {
-               ERROR("lxc.tty must be 0\n");
-               return false;
-       }
-
-       lxc_list_for_each(it, &c->lxc_conf->cgroup) {
-               struct lxc_cgroup *cg = it->elem;
-               if (strcmp(cg->subsystem, "devices.deny") == 0 &&
-                               strcmp(cg->value, "c 5:1 rwm") == 0) {
-
-                       found_deny_rule = true;
-                       break;
-               }
-       }
-
-       if (!found_deny_rule) {
-               ERROR("couldn't find devices.deny = c 5:1 rwm");
-               return false;
-       }
-
        return true;
 }
 
@@ -384,12 +554,14 @@ out_unlock:
        return !has_error;
 }
 
-void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
+// do_restore never returns, the calling process is used as the
+// monitor process. do_restore calls exit() if it fails.
+void do_restore(struct lxc_container *c, int status_pipe, char *directory, bool verbose)
 {
        pid_t pid;
        char pidfile[L_tmpnam];
        struct lxc_handler *handler;
-       int status;
+       int status, pipes[2] = {-1, -1};
 
        if (!tmpnam(pidfile))
                goto out;
@@ -415,6 +587,11 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
 
        resolve_clone_flags(handler);
 
+       if (pipe(pipes) < 0) {
+               SYSERROR("pipe() failed");
+               goto out_fini_handler;
+       }
+
        pid = fork();
        if (pid < 0)
                goto out_fini_handler;
@@ -422,9 +599,22 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
        if (pid == 0) {
                struct criu_opts os;
                struct lxc_rootfs *rootfs;
+               int flags;
+
+               close(status_pipe);
+               status_pipe = -1;
+
+               close(pipes[0]);
+               pipes[0] = -1;
+               if (dup2(pipes[1], STDERR_FILENO) < 0) {
+                       SYSERROR("dup2 failed");
+                       goto out_fini_handler;
+               }
 
-               close(pipe);
-               pipe = -1;
+               if (dup2(pipes[1], STDOUT_FILENO) < 0) {
+                       SYSERROR("dup2 failed");
+                       goto out_fini_handler;
+               }
 
                if (unshare(CLONE_NEWNS))
                        goto out_fini_handler;
@@ -457,6 +647,26 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
                os.pidfile = pidfile;
                os.verbose = verbose;
                os.cgroup_path = cgroup_canonical_path(handler);
+               os.console_fd = c->lxc_conf->console.slave;
+
+               if (os.console_fd >= 0) {
+                       /* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
+                        * via --inherit-fd, so we don't want it to close.
+                        */
+                       flags = fcntl(os.console_fd, F_GETFD);
+                       if (flags < 0) {
+                               SYSERROR("F_GETFD failed: %d", os.console_fd);
+                               goto out_fini_handler;
+                       }
+
+                       flags &= ~FD_CLOEXEC;
+
+                       if (fcntl(os.console_fd, F_SETFD, flags) < 0) {
+                               SYSERROR("F_SETFD failed");
+                               goto out_fini_handler;
+                       }
+               }
+               os.console_name = c->lxc_conf->console.name;
 
                /* exec_criu() returning is an error */
                exec_criu(&os);
@@ -467,15 +677,18 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
                int ret;
                char title[2048];
 
+               close(pipes[1]);
+               pipes[1] = -1;
+
                pid_t w = waitpid(pid, &status, 0);
                if (w == -1) {
                        SYSERROR("waitpid");
                        goto out_fini_handler;
                }
 
-               ret = write(pipe, &status, sizeof(status));
-               close(pipe);
-               pipe = -1;
+               ret = write(status_pipe, &status, sizeof(status));
+               close(status_pipe);
+               status_pipe = -1;
 
                if (sizeof(status) != ret) {
                        SYSERROR("failed to write all of status");
@@ -484,6 +697,18 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
 
                if (WIFEXITED(status)) {
                        if (WEXITSTATUS(status)) {
+                               char buf[4096];
+                               int n;
+
+                               n = read(pipes[0], buf, sizeof(buf));
+                               if (n < 0) {
+                                       SYSERROR("failed reading from criu stderr");
+                                       goto out_fini_handler;
+                               }
+
+                               buf[n] = 0;
+
+                               ERROR("criu process exited %d, output:\n%s\n", WEXITSTATUS(status), buf);
                                goto out_fini_handler;
                        } else {
                                int ret;
@@ -503,14 +728,18 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
                                        goto out_fini_handler;
                                }
 
-                               if (lxc_set_state(c->name, handler, RUNNING))
+                               if (lxc_set_state(c->name, handler, RUNNING)) {
+                                       ERROR("error setting running state after restore");
                                        goto out_fini_handler;
+                               }
                        }
                } else {
                        ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
                        goto out_fini_handler;
                }
 
+               close(pipes[0]);
+
                /*
                 * See comment in lxcapi_start; we don't care if these
                 * fail because it's just a beauty thing. We just
@@ -527,18 +756,213 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
        }
 
 out_fini_handler:
+       if (pipes[0] >= 0)
+               close(pipes[0]);
+       if (pipes[1] >= 0)
+               close(pipes[1]);
+
        lxc_fini(c->name, handler);
        if (unlink(pidfile) < 0 && errno != ENOENT)
                SYSERROR("unlinking pidfile failed");
 
 out:
-       if (pipe >= 0) {
+       if (status_pipe >= 0) {
                status = 1;
-               if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
+               if (write(status_pipe, &status, sizeof(status)) != sizeof(status)) {
                        SYSERROR("writing status failed");
                }
-               close(pipe);
+               close(status_pipe);
        }
 
        exit(1);
 }
+
+static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len)
+{
+       FILE *f;
+       char path[PATH_MAX];
+       int ret;
+       struct stat sb;
+
+       if (c->lxc_conf->console.path && !strcmp(c->lxc_conf->console.path, "none")) {
+               tty_id[0] = 0;
+               return 0;
+       }
+
+       ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/console", c->init_pid(c));
+       if (ret < 0 || ret >= sizeof(path)) {
+               ERROR("snprintf'd too many chacters: %d", ret);
+               return -1;
+       }
+
+       ret = stat(path, &sb);
+       if (ret < 0) {
+               SYSERROR("stat of %s failed", path);
+               return -1;
+       }
+
+       ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
+       if (ret < 0 || ret >= sizeof(path)) {
+               ERROR("snprintf'd too many characters: %d", ret);
+               return -1;
+       }
+
+       ret = snprintf(tty_id, len, "tty[%llx:%llx]",
+                                       (long long unsigned) sb.st_rdev,
+                                       (long long unsigned) sb.st_dev);
+       if (ret < 0 || ret >= sizeof(path)) {
+               ERROR("snprintf'd too many characters: %d", ret);
+               return -1;
+       }
+
+       f = fopen(path, "w");
+       if (!f) {
+               SYSERROR("failed to open %s", path);
+               return -1;
+       }
+
+       ret = fprintf(f, "%s", tty_id);
+       fclose(f);
+       if (ret < 0)
+               SYSERROR("failed to write to %s", path);
+       return ret;
+}
+
+/* do one of either predump or a regular dump */
+static bool do_dump(struct lxc_container *c, char *mode, char *directory,
+                   bool stop, bool verbose, char *predump_dir,
+                   char *pageserver_address, char *pageserver_port)
+{
+       pid_t pid;
+
+       if (!criu_ok(c))
+               return false;
+
+       if (mkdir_p(directory, 0700) < 0)
+               return false;
+
+       pid = fork();
+       if (pid < 0) {
+               SYSERROR("fork failed");
+               return false;
+       }
+
+       if (pid == 0) {
+               struct criu_opts os;
+
+               os.action = mode;
+               os.directory = directory;
+               os.c = c;
+               os.stop = stop;
+               os.verbose = verbose;
+               os.predump_dir = predump_dir;
+               os.console_name = c->lxc_conf->console.path;
+               os.pageserver_address = pageserver_address;
+               os.pageserver_port = pageserver_port;
+
+               if (save_tty_major_minor(directory, c, os.tty_id, sizeof(os.tty_id)) < 0)
+                       exit(1);
+
+               /* exec_criu() returning is an error */
+               exec_criu(&os);
+               exit(1);
+       } else {
+               int status;
+               pid_t w = waitpid(pid, &status, 0);
+               if (w == -1) {
+                       SYSERROR("waitpid");
+                       return false;
+               }
+
+               if (WIFEXITED(status)) {
+                       if (WEXITSTATUS(status)) {
+                               ERROR("dump failed with %d\n", WEXITSTATUS(status));
+                               return false;
+                       }
+
+                       return true;
+               } else if (WIFSIGNALED(status)) {
+                       ERROR("dump signaled with %d\n", WTERMSIG(status));
+                       return false;
+               } else {
+                       ERROR("unknown dump exit %d\n", status);
+                       return false;
+               }
+       }
+}
+
+bool __criu_pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir, char *pageserver_address, char *pageserver_port)
+{
+       return do_dump(c, "pre-dump", directory, false, verbose, predump_dir, pageserver_address, pageserver_port);
+}
+
+bool __criu_dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir, char *pageserver_address, char *pageserver_port)
+{
+       char path[PATH_MAX];
+       int ret;
+
+       ret = snprintf(path, sizeof(path), "%s/inventory.img", directory);
+       if (ret < 0 || ret >= sizeof(path))
+               return false;
+
+       if (access(path, F_OK) == 0) {
+               ERROR("please use a fresh directory for the dump directory\n");
+               return false;
+       }
+
+       return do_dump(c, "dump", directory, stop, verbose, predump_dir, pageserver_address, pageserver_port);
+}
+
+bool __criu_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;
+}
index df63625..db2ab11 100644 (file)
 
 #include <lxc/lxccontainer.h>
 
-// We require either the criu major/minor version, or the criu GITID if criu
-// was built from git.
-#define CRIU_VERSION           "1.6"
-
-#define CRIU_GITID_VERSION     "1.5"
-#define CRIU_GITID_PATCHLEVEL  133
-
-struct criu_opts {
-       /* The type of criu invocation, one of "dump" or "restore" */
-       char *action;
-
-       /* The directory to pass to criu */
-       char *directory;
-
-       /* The container to dump */
-       struct lxc_container *c;
-
-       /* Enable criu verbose mode? */
-       bool verbose;
-
-       /* dump: stop the container or not after dumping? */
-       bool stop;
-
-       /* restore: the file to write the init process' pid into */
-       char *pidfile;
-       const char *cgroup_path;
-};
-
-void exec_criu(struct criu_opts *opts);
-
-/* Check and make sure the container has a configuration that we know CRIU can
- * dump. */
-bool criu_ok(struct lxc_container *c);
-
-// do_restore never returns, the calling process is used as the
-// monitor process. do_restore calls exit() if it fails.
-void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose);
+bool __criu_pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir, char *pageserver_address, char *pageserver_port);
+bool __criu_dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir, char *pageserver_address, char *pageserver_port);
+bool __criu_restore(struct lxc_container *c, char *directory, bool verbose);
 
 #endif
index dbb5d52..8d9016c 100644 (file)
@@ -47,6 +47,10 @@ extern void lxc_setup_fs(void)
        if (mount_fs("proc", "/proc", "proc"))
                INFO("failed to remount proc");
 
+       /* if /dev has been populated by us, /dev/shm does not exist */
+       if (access("/dev/shm", F_OK) && mkdir("/dev/shm", 0777))
+               INFO("failed to create /dev/shm");
+
        /* if we can't mount /dev/shm, continue anyway */
        if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
                INFO("failed to mount /dev/shm");
@@ -87,6 +91,7 @@ const char *lxc_global_config_value(const char *option_name)
                { "lxc.bdev.lvm.vg",        DEFAULT_VG      },
                { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
                { "lxc.bdev.zfs.root",      DEFAULT_ZFSROOT },
+               { "lxc.bdev.rbd.rbdpool",   DEFAULT_RBDPOOL },
                { "lxc.lxcpath",            NULL            },
                { "lxc.default_config",     NULL            },
                { "lxc.cgroup.pattern",     NULL            },
index b4f9e54..c021fd6 100644 (file)
@@ -42,6 +42,7 @@
 #define DEFAULT_VG "lxc"
 #define DEFAULT_THIN_POOL "lxc"
 #define DEFAULT_ZFSROOT "lxc"
+#define DEFAULT_RBDPOOL "lxc"
 
 extern void lxc_setup_fs(void);
 extern const char *lxc_global_config_value(const char *option_name);
diff --git a/src/lxc/legacy/lxc-ls.in b/src/lxc/legacy/lxc-ls.in
deleted file mode 100644 (file)
index a823bd0..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/sh
-
-#
-# lxc: linux Container library
-
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-. @DATADIR@/lxc/lxc.functions
-
-usage()
-{
-       echo "usage: $(basename $0) [--active] [--] [LS_OPTIONS...]" >&2
-}
-
-help() {
-       usage
-       echo >&2
-       echo "List containers existing on the system." >&2
-       echo >&2
-       echo "  --active     list active containers" >&2
-       echo "  LS_OPTIONS   ls command options (see \`ls --help')" >&2
-}
-
-get_parent_cgroup()
-{
-       parent_cgroup=""
-
-       # Obtain a list of hierarchies that contain one or more subsystems
-       hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
-
-       # Iterate through the list until a suitable hierarchy is found
-       for hierarchy in $hierarchies; do
-               # Obtain information about the init process in the hierarchy
-               fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
-               if [ -z "$fields" ]; then continue; fi
-               fields=${fields#*:}
-
-               # Get a comma-separated list of the hierarchy's subsystems
-               subsystems=${fields%:*}
-
-               # Get the cgroup of the init process in the hierarchy
-               init_cgroup=${fields#*:}
-
-               # Get the filesystem mountpoint of the hierarchy
-               mountpoint=$(awk -v subsysregex="(^|,)$subsystems(,|\$)" \
-                       '$3 == "cgroup" && $4 ~ subsysregex {print $2}' /proc/self/mounts)
-               if [ -z "$mountpoint" ]; then continue; fi
-
-               # Return the absolute path to the containers' parent cgroup
-               # (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
-               case ",$subsystems," in
-                       *,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
-                       *) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
-               esac
-               break
-       done
-}
-
-directory=$(readlink -f "$lxc_path")
-
-for i in "$@"; do
-       case $i in
-               --help)
-                       help; exit;;
-               --active)
-                       get_parent_cgroup; directory="$parent_cgroup"; shift;;
-               --)
-                       shift; break;;
-               *)
-                       break;;
-       esac
-done
-
-containers=""
-if [ ! -z "$directory" ]; then
-       if [ x"$parent_cgroup" = x ]; then
-               containers=$(find -L $directory -mindepth 2 -maxdepth 2 -name config -type f |awk -F "/" '{print $(NF-1)}')
-       else
-               containers=$(find $directory -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')
-       fi
-       if [ x"$containers" = x ]; then
-               exit 0
-       fi
-fi
-
-cd "$directory"
-ls -d $@ -- $containers
index 2d8a2a8..91ea3a4 100644 (file)
@@ -32,42 +32,71 @@ struct lxc_list {
 
 #define lxc_init_list(l) { .next = l, .prev = l }
 
+/*
+ * Iterate through an lxc list. An example for an idiom would be:
+ *
+ * struct lxc_list *iterator;
+ * type *tmp; // where "type" can be an int, char * etc.
+ * lxc_list_for_each(iterator, list) {
+ *       tmp = iterator->elem;
+ *        // Do stuff with tmp.
+ * }
+ * free(iterator);
+ */
 #define lxc_list_for_each(__iterator, __list)                          \
        for (__iterator = (__list)->next;                               \
             __iterator != __list;                                      \
             __iterator = __iterator->next)
 
+/*
+ * Iterate safely through an lxc list. An example for an appropriate use case
+ * would be:
+ *
+ * struct lxc_list *iterator;
+ * lxc_list_for_each_safe(iterator, list, list->next) {
+ *       tmp = iterator->elem;
+ *        // Do stuff with tmp.
+ * }
+ * free(iterator);
+ */
 #define lxc_list_for_each_safe(__iterator, __list, __next)             \
        for (__iterator = (__list)->next, __next = __iterator->next;    \
             __iterator != __list;                                      \
             __iterator = __next, __next = __next->next)
 
+/* Initalize list. */
 static inline void lxc_list_init(struct lxc_list *list)
 {
        list->elem = NULL;
        list->next = list->prev = list;
 }
 
+/* Add an element to a list. See lxc_list_add() and lxc_list_add_tail() for an
+ * idiom. */
 static inline void lxc_list_add_elem(struct lxc_list *list, void *elem)
 {
        list->elem = elem;
 }
 
+/* Retrieve first element of list. */
 static inline void *lxc_list_first_elem(struct lxc_list *list)
 {
        return list->next->elem;
 }
 
+/* Retrieve last element of list. */
 static inline void *lxc_list_last_elem(struct lxc_list *list)
 {
        return list->prev->elem;
 }
 
+/* Determine if list is empty. */
 static inline int lxc_list_empty(struct lxc_list *list)
 {
        return list == list->next;
 }
 
+/* Workhorse to be called from lxc_list_add() and lxc_list_add_tail(). */
 static inline void __lxc_list_add(struct lxc_list *new,
                                  struct lxc_list *prev,
                                  struct lxc_list *next)
@@ -78,17 +107,44 @@ static inline void __lxc_list_add(struct lxc_list *new,
        prev->next = new;
 }
 
+/*
+ * Idiom to add an element to the beginning of an lxc list:
+ *
+ *     struct lxc_list *tmp = malloc(sizeof(*tmp));
+ *     if (tmp == NULL)
+ *             return 1;
+ *     lxc_list_add_elem(tmp, elem);
+ *     lxc_list_add(list, tmp);
+ */
 static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list)
 {
        __lxc_list_add(list, head, head->next);
 }
 
+/*
+ * Idiom to add an element to the end of an lxc list:
+ *
+ *     struct lxc_list *tmp = malloc(sizeof(*tmp));
+ *     if (tmp == NULL)
+ *             return 1;
+ *     lxc_list_add_elem(tmp, elem);
+ *     lxc_list_add_tail(list, tmp);
+ */
 static inline void lxc_list_add_tail(struct lxc_list *head,
                                     struct lxc_list *list)
 {
        __lxc_list_add(list, head->prev, head);
 }
 
+/*
+ * Idiom to free an lxc list:
+ *
+ * lxc_list_for_each_safe(iterator, list, list->next) {
+ *       lxc_list_del(iterator);
+ *       free(iterator);
+ * }
+ * free(iterator);
+ */
 static inline void lxc_list_del(struct lxc_list *list)
 {
        struct lxc_list *next, *prev;
@@ -99,9 +155,10 @@ static inline void lxc_list_del(struct lxc_list *list)
        prev->next = next;
 }
 
-static inline int lxc_list_len(struct lxc_list *list)
+/* Return length of the list. */
+static inline size_t lxc_list_len(struct lxc_list *list)
 {
-        int i = 0;
+        size_t i = 0;
         struct lxc_list *iter;
         lxc_list_for_each(iter, list) {
                i++;
index 6726cf0..55fa7f5 100644 (file)
@@ -20,6 +20,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+#include <assert.h>
 #include <stdio.h>
 #include <errno.h>
 #include <limits.h>
@@ -28,6 +29,7 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <pthread.h>
+#include <time.h>
 
 #define __USE_GNU /* for *_CLOEXEC */
 
@@ -40,6 +42,7 @@
 
 #define LXC_LOG_PREFIX_SIZE    32
 #define LXC_LOG_BUFFER_SIZE    512
+#define LXC_LOG_DATEFOMAT_SIZE  15
 
 int lxc_log_fd = -1;
 int lxc_quiet_specified;
@@ -69,7 +72,9 @@ static int log_append_stderr(const struct lxc_log_appender *appender,
 static int log_append_logfile(const struct lxc_log_appender *appender,
                              struct lxc_log_event *event)
 {
+       char date[LXC_LOG_DATEFOMAT_SIZE] = "20150427012246";
        char buffer[LXC_LOG_BUFFER_SIZE];
+       const struct tm *t;
        int n;
        int ms;
        int fd_to_use = -1;
@@ -85,11 +90,13 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
        if (fd_to_use == -1)
                return 0;
 
+       t = localtime(&event->timestamp.tv_sec);
+       strftime(date, sizeof(date), "%Y%m%d%H%M%S", t);
        ms = event->timestamp.tv_usec / 1000;
        n = snprintf(buffer, sizeof(buffer),
-                    "%15s %10ld.%03d %-8s %s - %s:%s:%d - ",
+                    "%15s %10s.%03d %-8s %s - %s:%s:%d - ",
                     log_prefix,
-                    event->timestamp.tv_sec,
+                    date,
                     ms,
                     lxc_log_priority_to_string(event->priority),
                     event->category,
@@ -246,6 +253,16 @@ static char *build_log_path(const char *name, const char *lxcpath)
        return p;
 }
 
+extern void lxc_log_close(void)
+{
+       if (lxc_log_fd == -1)
+               return;
+       close(lxc_log_fd);
+       lxc_log_fd = -1;
+       free(log_fname);
+       log_fname = NULL;
+}
+
 /*
  * This can be called:
  *   1. when a program calls lxc_log_init with no logfile parameter (in which
@@ -258,11 +275,12 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
 {
        if (lxc_log_fd != -1) {
                // we are overriding the default.
-               close(lxc_log_fd);
-               free(log_fname);
+               lxc_log_close();
        }
 
-       if (!fname || strlen(fname) == 0) {
+       assert(fname != NULL);
+
+       if (strlen(fname) == 0) {
                log_fname = NULL;
                return 0;
        }
@@ -374,16 +392,6 @@ extern int lxc_log_init(const char *name, const char *file,
        return ret;
 }
 
-extern void lxc_log_close(void)
-{
-       if (lxc_log_fd == -1)
-               return;
-       close(lxc_log_fd);
-       lxc_log_fd = -1;
-       free(log_fname);
-       log_fname = NULL;
-}
-
 /*
  * This is called when we read a lxc.loglevel entry in a lxc.conf file.  This
  * happens after processing command line arguments, which override the .conf
index 88ea5a3..c0b2e34 100644 (file)
@@ -31,6 +31,7 @@
 #include "log.h"
 #include "lsm/lsm.h"
 #include "conf.h"
+#include "utils.h"
 
 lxc_log_define(lxc_apparmor, lxc);
 
@@ -40,8 +41,10 @@ static int aa_enabled = 0;
 static int mount_features_enabled = 0;
 
 #define AA_DEF_PROFILE "lxc-container-default"
+#define AA_DEF_PROFILE_CGNS "lxc-container-default-cgns"
 #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
 #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
+#define AA_UNCHANGED "unchanged"
 
 static bool check_mount_feature_enabled(void)
 {
@@ -126,16 +129,36 @@ again:
        return buf;
 }
 
-static int apparmor_am_unconfined(void)
+/*
+ * Probably makes sense to reorganize these to only read
+ * the label once
+ */
+static bool apparmor_am_unconfined(void)
 {
        char *p = apparmor_process_label_get(getpid());
-       int ret = 0;
+       bool ret = false;
        if (!p || strcmp(p, "unconfined") == 0)
-               ret = 1;
+               ret = true;
        free(p);
        return ret;
 }
 
+/* aa stacking is not yet supported */
+static bool aa_stacking_supported(void) {
+       return false;
+}
+
+static bool aa_needs_transition(char *curlabel)
+{
+       if (!curlabel)
+               return false;
+       if (strcmp(curlabel, "unconfined") == 0)
+               return false;
+       if (strcmp(curlabel, "/usr/bin/lxc-start") == 0)
+               return false;
+       return true;
+}
+
 /*
  * apparmor_process_label_set: Set AppArmor process profile
  *
@@ -152,13 +175,41 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf
                                      int use_default, int on_exec)
 {
        const char *label = inlabel ? inlabel : conf->lsm_aa_profile;
+       char *curlabel;
 
        if (!aa_enabled)
                return 0;
 
+       /* user may request that we just ignore apparmor */
+       if (label && strcmp(label, AA_UNCHANGED) == 0) {
+               INFO("apparmor profile unchanged per user request");
+               return 0;
+       }
+
+       curlabel = apparmor_process_label_get(getpid());
+
+       if (!aa_stacking_supported() && aa_needs_transition(curlabel)) {
+               // we're already confined, and stacking isn't supported
+
+               if (!label || strcmp(curlabel, label) == 0) {
+                       // no change requested
+                       free(curlabel);
+                       return 0;
+               }
+
+               ERROR("already apparmor confined, but new label requested.");
+               free(curlabel);
+               return -1;
+       }
+       free(curlabel);
+
        if (!label) {
-               if (use_default)
-                       label = AA_DEF_PROFILE;
+               if (use_default) {
+                       if (cgns_supported())
+                               label = AA_DEF_PROFILE_CGNS;
+                       else
+                               label = AA_DEF_PROFILE;
+               }
                else
                        label = "unconfined";
        }
index 247b70f..835202b 100644 (file)
@@ -1,17 +1,18 @@
 #!/bin/sh
 
-# Allow environment variables to override grep and config
+# Allow environment variables to override config
 : ${CONFIG:=/proc/config.gz}
-: ${GREP:=zgrep}
 : ${MODNAME:=configs}
 
+CAT="cat"
+
 SETCOLOR_SUCCESS="printf \\033[1;32m"
 SETCOLOR_FAILURE="printf \\033[1;31m"
 SETCOLOR_WARNING="printf \\033[1;33m"
 SETCOLOR_NORMAL="printf \\033[0;39m"
 
 is_set() {
-    $GREP "$1=[y|m]" $CONFIG > /dev/null
+    $CAT $CONFIG | grep "$1=[y|m]" > /dev/null
     return $?
 }
 
@@ -45,7 +46,6 @@ if [ ! -f $CONFIG ]; then
         # although scripts/extract-ikconfig could be used to extract contents without loading kernel module
         # http://svn.pld-linux.org/trac/svn/browser/geninitrd/trunk/geninitrd?rev=12696#L327
     fi
-    GREP=grep
     if [ ! -f $CONFIG ]; then
         echo "$(basename $0): unable to retrieve kernel configuration" >&2
         echo >&2
@@ -61,6 +61,10 @@ if [ ! -f $CONFIG ]; then
     fi
 fi
 
+if gunzip -tq < $CONFIG 2>/dev/null; then
+    CAT="zcat"
+fi
+
 echo "--- Namespaces ---"
 echo -n "Namespaces: " && is_enabled CONFIG_NAMESPACES yes
 echo -n "Utsname namespace: " && is_enabled CONFIG_UTS_NS
@@ -78,13 +82,13 @@ print_cgroups() {
 }
 
 CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -n 1`
-KVER_MAJOR=$($GREP '^# Linux.*Kernel Configuration' $CONFIG | \
+KVER_MAJOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
     sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
 if [ "$KVER_MAJOR" = "2" ]; then
-KVER_MINOR=$($GREP '^# Linux.*Kernel Configuration' $CONFIG | \
+KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
     sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
 else
-KVER_MINOR=$($GREP '^# Linux.*Kernel Configuration' $CONFIG | \
+KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
     sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
 fi
 
@@ -118,6 +122,7 @@ echo -n "CONFIG_NF_NAT_IPV6: " && is_enabled CONFIG_NF_NAT_IPV6
 echo -n "CONFIG_IP_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP_NF_TARGET_MASQUERADE
 echo -n "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE
 echo -n "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM
+echo -n "FUSE (for use with lxcfs): " && is_enabled CONFIG_FUSE_FS
 
 echo
 echo "--- Checkpoint/Restore ---"
diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls
deleted file mode 100644 (file)
index b136aa5..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-#!/usr/bin/python3
-#
-# lxc-ls: List containers
-#
-# This python implementation is based on the work done in the original
-# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
-#
-# (C) Copyright Canonical Ltd. 2012
-#
-# Authors:
-# Stéphane Graber <stgraber@ubuntu.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-
-import argparse
-import gettext
-import json
-import lxc
-import os
-import re
-import shutil
-import tempfile
-import sys
-
-_ = gettext.gettext
-gettext.textdomain("lxc-ls")
-
-# Required for containers without python
-import encodings.ascii
-assert encodings.ascii
-
-# Constants
-LXCPATH = "/usr/local/var/lib/lxc"
-RUNTIME_PATH = "/run"
-
-
-# Functions used later on
-def batch(iterable, cols=1):
-    import math
-
-    length = len(iterable)
-    lines = math.ceil(length / cols)
-
-    for line in range(lines):
-        fields = []
-        for col in range(cols):
-            index = line + (col * lines)
-            if index < length:
-                fields.append(iterable[index])
-        yield fields
-
-
-def get_terminal_size():
-    import os
-    env = os.environ
-
-    def ioctl_GWINSZ(fd):
-        try:
-            import fcntl
-            import termios
-            import struct
-            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
-                               '1234'))
-            return cr
-        except:
-            return
-
-    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
-    if not cr:
-        try:
-            fd = os.open(os.ctermid(), os.O_RDONLY)
-            cr = ioctl_GWINSZ(fd)
-            os.close(fd)
-        except:
-            pass
-
-    if not cr:
-        cr = (env.get('LINES', 25), env.get('COLUMNS', 80))
-
-    return int(cr[1]), int(cr[0])
-
-
-def get_root_path(path):
-    lxc_path = LXCPATH
-    global_conf = "%s/etc/lxc/lxc.conf" % path
-    if os.path.exists(global_conf):
-        with open(global_conf, "r") as fd:
-            for line in fd:
-                if line.startswith("lxc.lxcpath"):
-                    lxc_path = line.split("=")[-1].strip()
-                    break
-    return lxc_path
-
-
-# Constants
-FIELDS = ("name", "state", "interfaces", "ipv4", "ipv6", "autostart", "pid",
-          "memory", "ram", "swap", "groups")
-DEFAULT_FIELDS = ("name", "state", "ipv4", "ipv6", "groups", "autostart")
-
-# Begin parsing the command line
-parser = argparse.ArgumentParser(description=_("LXC: List containers"),
-                                 formatter_class=argparse.RawTextHelpFormatter,
-                                 epilog=_("""Valid fancy-format fields:
-  %s
-
-Default fancy-format fields:
-  %s\n""" % (", ".join(FIELDS), ", ".join(DEFAULT_FIELDS))))
-
-parser.add_argument("-1", dest="one", action="store_true",
-                    help=_("list one container per line (default when piped)"))
-
-parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH",
-                    help=_("Use specified container path"),
-                    default=lxc.default_config_path)
-
-parser.add_argument("--active", action="store_true",
-                    help=_("list only active containers"))
-
-parser.add_argument("--frozen", dest="state", action="append_const",
-                    const="FROZEN", help=_("list only frozen containers"))
-
-parser.add_argument("--running", dest="state", action="append_const",
-                    const="RUNNING", help=_("list only running containers"))
-
-parser.add_argument("--stopped", dest="state", action="append_const",
-                    const="STOPPED", help=_("list only stopped containers"))
-
-parser.add_argument("-f", "--fancy", action="store_true",
-                    help=_("use fancy output"))
-
-parser.add_argument("-F", "--fancy-format", type=str,
-                    default=",".join(DEFAULT_FIELDS),
-                    help=_("comma separated list of fields to show"))
-
-parser.add_argument("-g", "--groups", type=str, action="append",
-                    metavar="GROUPS",
-                    help=_("groups (comma separated) the container must "
-                           "be a member of"))
-
-parser.add_argument("--nesting", dest="nesting", action="store_true",
-                    help=_("show nested containers"))
-
-parser.add_argument("filter", metavar='FILTER', type=str, nargs="?",
-                    help=_("regexp to be applied on the container list"))
-
-parser.add_argument("--version", action="version", version=lxc.version)
-
-args = parser.parse_args()
-
-# --active is the same as --running --frozen
-if args.active:
-    if not args.state:
-        args.state = []
-    args.state += ["RUNNING", "FROZEN", "UNKNOWN"]
-
-# If the output is piped, default to --one
-if not sys.stdout.isatty():
-    args.one = True
-
-# Turn args.fancy_format into a list
-args.fancy_format = args.fancy_format.strip().split(",")
-
-if set(args.fancy_format) - set(FIELDS):
-    parser.error(_("Invalid field(s): %s" %
-                 ", ".join(list(set(args.fancy_format) - set(FIELDS)))))
-
-# Basic checks
-## Check for setns
-SUPPORT_SETNS = os.path.exists("/proc/self/ns")
-SUPPORT_SETNS_NET = False
-SUPPORT_SETNS_PID = False
-if SUPPORT_SETNS:
-    SUPPORT_SETNS_NET = os.path.exists("/proc/self/ns/net")
-    SUPPORT_SETNS_PID = os.path.exists("/proc/self/ns/pid")
-
-## Nesting requires setns to pid and net ns
-if args.nesting:
-    if not SUPPORT_SETNS:
-        parser.error(_("Showing nested containers requires setns support "
-                       "which your kernel doesn't support."))
-
-    if not SUPPORT_SETNS_NET:
-        parser.error(_("Showing nested containers requires setns to the "
-                       "network namespace which your kernel doesn't support."))
-
-    if not SUPPORT_SETNS_PID:
-        parser.error(_("Showing nested containers requires setns to the "
-                       "PID namespace which your kernel doesn't support."))
-
-# Set the actual lxcpath value
-if not args.lxcpath:
-    args.lxcpath = lxc.default_config_path
-
-
-# List of containers, stored as dictionaries
-def get_containers(fd=None, base="/", root=False):
-    containers = []
-
-    paths = [args.lxcpath]
-
-    if not root:
-        paths.append(get_root_path(base))
-
-    # Generate a unique list of valid paths
-    paths = set([os.path.normpath("%s/%s" % (base, path)) for path in paths])
-
-    for path in paths:
-        if not os.access(path, os.R_OK):
-            continue
-
-        for container_name in lxc.list_containers(config_path=path):
-            entry = {}
-            entry['name'] = container_name
-
-            # Apply filter
-            if root and args.filter and \
-               not re.match(args.filter, container_name):
-                continue
-
-            # Return before grabbing the object (non-root)
-            if not args.state and not args.fancy and not args.nesting \
-                    and not args.groups:
-                containers.append(entry)
-                continue
-
-            try:
-                container = lxc.Container(container_name, path)
-            except:
-                continue
-
-            if args.groups or "autostart" in args.fancy_format \
-                    or "groups" in args.fancy_format:
-                try:
-                    groups = container.get_config_item("lxc.group")
-                except KeyError:
-                    groups = []
-
-            if args.groups:
-                set_has = set(groups)
-
-                for group in args.groups:
-                    set_must = set(group.split(","))
-                    if not set_must - set_has:
-                        break
-                else:
-                    continue
-
-            if container.controllable:
-                state = container.state
-            else:
-                state = 'UNKNOWN'
-
-            # Filter by status
-            if args.state and state not in args.state:
-                continue
-
-            # Nothing more is needed if we're not printing some fancy output
-            if not args.fancy and not args.nesting:
-                containers.append(entry)
-                continue
-
-            # Some extra field we may want
-            if 'state' in args.fancy_format:
-                entry['state'] = state
-
-            if 'pid' in args.fancy_format:
-                entry['pid'] = "-"
-                if state == 'UNKNOWN':
-                    entry['pid'] = state
-                elif container.init_pid != -1:
-                    entry['pid'] = str(container.init_pid)
-
-            if 'groups' in args.fancy_format:
-                entry['groups'] = "-"
-                if len(groups) > 0:
-                    entry['groups'] = ", ".join(groups)
-
-            if 'autostart' in args.fancy_format:
-                entry['autostart'] = "NO"
-                try:
-                    if container.get_config_item("lxc.start.auto") == "1":
-                        if len(groups) > 0:
-                            entry['autostart'] = "BY-GROUP"
-                        else:
-                            entry['autostart'] = "YES"
-                except KeyError:
-                    pass
-
-            if 'memory' in args.fancy_format or \
-               'ram' in args.fancy_format or \
-               'swap' in args.fancy_format:
-
-                if container.running:
-                    try:
-                        memory_ram = int(container.get_cgroup_item(
-                            "memory.usage_in_bytes"))
-                    except:
-                        memory_ram = 0
-
-                    try:
-                        memory_swap = int(container.get_cgroup_item(
-                            "memory.memsw.usage_in_bytes")) - memory_ram
-                    except:
-                        memory_swap = 0
-                else:
-                    memory_ram = 0
-                    memory_swap = 0
-
-                memory_total = memory_ram + memory_swap
-
-            if 'memory' in args.fancy_format:
-                if container.running:
-                    entry['memory'] = "%sMB" % round(memory_total / 1048576, 2)
-                else:
-                    entry['memory'] = "-"
-
-            if 'ram' in args.fancy_format:
-                if container.running:
-                    entry['ram'] = "%sMB" % round(memory_ram / 1048576, 2)
-                else:
-                    entry['ram'] = "-"
-
-            if 'swap' in args.fancy_format:
-                if container.running:
-                    entry['swap'] = "%sMB" % round(memory_swap / 1048576, 2)
-                else:
-                    entry['swap'] = "-"
-
-            # Get the IPs
-            for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
-                if protocol in args.fancy_format:
-                    entry[protocol] = "-"
-
-                    if state == 'UNKNOWN':
-                        entry[protocol] = state
-                        continue
-
-                    if container.running:
-                        if not SUPPORT_SETNS_NET:
-                            entry[protocol] = 'UNKNOWN'
-                            continue
-
-                        ips = container.get_ips(family=family)
-                        if ips:
-                            entry[protocol] = ", ".join(ips)
-
-            # Get the interfaces
-            if 'interfaces' in args.fancy_format:
-                entry['interfaces'] = "-"
-
-                if state == 'UNKNOWN' or (container.running and
-                                          not SUPPORT_SETNS_NET):
-                    entry['interfaces'] = "UNKNOWN"
-                elif container.running:
-                    interfaces = container.get_interfaces()
-                    if interfaces:
-                        entry['interfaces'] = ", ".join(interfaces)
-
-            # Nested containers
-            if args.nesting:
-                if container.running:
-                    # Recursive call in container namespace
-                    temp_fd, temp_file = tempfile.mkstemp()
-                    os.remove(temp_file)
-
-                    container.attach_wait(get_containers, temp_fd)
-
-                    json_file = os.fdopen(temp_fd, "r")
-                    json_file.seek(0)
-
-                    try:
-                        sub_containers = json.loads(json_file.read())
-                    except:
-                        sub_containers = []
-
-                    json_file.close()
-                else:
-                    def clear_lock():
-                        try:
-                            lock_path = "%s/lock/lxc/%s/%s" % (RUNTIME_PATH,
-                                                               path,
-                                                               entry['name'])
-                            if os.path.exists(lock_path):
-                                if os.path.isdir(lock_path):
-                                    shutil.rmtree(lock_path)
-                                else:
-                                    os.remove(lock_path)
-                        except:
-                            pass
-
-                    clear_lock()
-
-                    # Recursive call using container rootfs
-                    sub_containers = get_containers(
-                        base="%s/%s" % (
-                            base, container.get_config_item("lxc.rootfs")))
-
-                    clear_lock()
-
-                for sub in sub_containers:
-                    if 'nesting_parent' not in sub:
-                        sub['nesting_parent'] = []
-                    sub['nesting_parent'].insert(0, entry['name'])
-                    sub['nesting_real_name'] = sub.get('nesting_real_name',
-                                                       sub['name'])
-                    sub['name'] = "%s/%s" % (entry['name'], sub['name'])
-                    containers.append(sub)
-
-            # Append the container
-            containers.append(entry)
-
-    if fd:
-        json_file = os.fdopen(fd, "w+")
-        json_file.write(json.dumps(containers))
-        return
-
-    return containers
-
-containers = get_containers(root=True)
-
-# Print the list
-## Standard list with one entry per line
-if not args.fancy and args.one:
-    for container in sorted(containers,
-                            key=lambda container: container['name']):
-        print(container['name'])
-    sys.exit(0)
-
-## Standard list with multiple entries per line
-if not args.fancy and not args.one:
-    # Get the longest name and extra simple list
-    field_maxlength = 0
-    container_names = []
-    for container in containers:
-        if len(container['name']) > field_maxlength:
-            field_maxlength = len(container['name'])
-        container_names.append(container['name'])
-
-    # Figure out how many we can put per line
-    width = get_terminal_size()[0]
-
-    entries = int(width / (field_maxlength + 2))
-    if entries == 0:
-        entries = 1
-
-    for line in batch(sorted(container_names), entries):
-        line_format = ""
-        for index in range(len(line)):
-            line_format += "{line[%s]:%s}" % (index, field_maxlength + 2)
-
-        print(line_format.format(line=line))
-
-## Fancy listing
-if args.fancy:
-    field_maxlength = {}
-
-    # Get the maximum length per field
-    for field in args.fancy_format:
-        field_maxlength[field] = len(field)
-
-    for container in containers:
-        for field in args.fancy_format:
-            if field == 'name' and 'nesting_real_name' in container:
-                fieldlen = len(" " * ((len(container['nesting_parent']) - 1)
-                               * 4) + " \_ " + container['nesting_real_name'])
-                if fieldlen > field_maxlength[field]:
-                    field_maxlength[field] = fieldlen
-            elif len(container[field]) > field_maxlength[field]:
-                field_maxlength[field] = len(container[field])
-
-    # Generate the line format string based on the maximum length and
-    # a 2 character padding
-    line_format = ""
-    index = 0
-    for field in args.fancy_format:
-        line_format += "{fields[%s]:%s}" % (index, field_maxlength[field] + 2)
-        index += 1
-
-    # Get the line length minus the padding of the last field
-    line_length = -2
-    for field in field_maxlength:
-        line_length += field_maxlength[field] + 2
-
-    # Print header
-    print(line_format.format(fields=[header.upper()
-                                     for header in args.fancy_format]))
-    print("-" * line_length)
-
-    # Print the entries
-    for container in sorted(containers,
-                            key=lambda container: container['name']):
-        fields = []
-        for field in args.fancy_format:
-            if field == 'name' and 'nesting_real_name' in container:
-                prefix = " " * ((len(container['nesting_parent']) - 1) * 4)
-                fields.append(prefix + " \_ " + container['nesting_real_name'])
-            else:
-                fields.append(container[field])
-
-        print(line_format.format(fields=fields))
diff --git a/src/lxc/lxc-ls.in b/src/lxc/lxc-ls.in
deleted file mode 100755 (executable)
index 280f48b..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-#!/usr/bin/python3
-#
-# lxc-ls: List containers
-#
-# This python implementation is based on the work done in the original
-# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
-#
-# (C) Copyright Canonical Ltd. 2012
-#
-# Authors:
-# Stéphane Graber <stgraber@ubuntu.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-
-import argparse
-import gettext
-import json
-import lxc
-import os
-import re
-import shutil
-import tempfile
-import sys
-
-_ = gettext.gettext
-gettext.textdomain("lxc-ls")
-
-# Required for containers without python
-import encodings.ascii
-assert encodings.ascii
-
-# Constants
-LXCPATH = "@LXCPATH@"
-RUNTIME_PATH = "@RUNTIME_PATH@"
-
-
-# Functions used later on
-def batch(iterable, cols=1):
-    import math
-
-    length = len(iterable)
-    lines = math.ceil(length / cols)
-
-    for line in range(lines):
-        fields = []
-        for col in range(cols):
-            index = line + (col * lines)
-            if index < length:
-                fields.append(iterable[index])
-        yield fields
-
-
-def get_terminal_size():
-    import os
-    env = os.environ
-
-    def ioctl_GWINSZ(fd):
-        try:
-            import fcntl
-            import termios
-            import struct
-            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
-                               '1234'))
-            return cr
-        except:
-            return
-
-    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
-    if not cr:
-        try:
-            fd = os.open(os.ctermid(), os.O_RDONLY)
-            cr = ioctl_GWINSZ(fd)
-            os.close(fd)
-        except:
-            pass
-
-    if not cr:
-        cr = (env.get('LINES', 25), env.get('COLUMNS', 80))
-
-    return int(cr[1]), int(cr[0])
-
-
-def get_root_path(path):
-    lxc_path = LXCPATH
-    global_conf = "%s/etc/lxc/lxc.conf" % path
-    if os.path.exists(global_conf):
-        with open(global_conf, "r") as fd:
-            for line in fd:
-                if line.startswith("lxc.lxcpath"):
-                    lxc_path = line.split("=")[-1].strip()
-                    break
-    return lxc_path
-
-
-# Constants
-FIELDS = ("name", "state", "interfaces", "ipv4", "ipv6", "autostart", "pid",
-          "memory", "ram", "swap", "groups")
-DEFAULT_FIELDS = ("name", "state", "ipv4", "ipv6", "groups", "autostart")
-
-# Begin parsing the command line
-parser = argparse.ArgumentParser(description=_("LXC: List containers"),
-                                 formatter_class=argparse.RawTextHelpFormatter,
-                                 epilog=_("""Valid fancy-format fields:
-  %s
-
-Default fancy-format fields:
-  %s\n""" % (", ".join(FIELDS), ", ".join(DEFAULT_FIELDS))))
-
-parser.add_argument("-1", dest="one", action="store_true",
-                    help=_("list one container per line (default when piped)"))
-
-parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH",
-                    help=_("Use specified container path"),
-                    default=lxc.default_config_path)
-
-parser.add_argument("--active", action="store_true",
-                    help=_("list only active containers"))
-
-parser.add_argument("--frozen", dest="state", action="append_const",
-                    const="FROZEN", help=_("list only frozen containers"))
-
-parser.add_argument("--running", dest="state", action="append_const",
-                    const="RUNNING", help=_("list only running containers"))
-
-parser.add_argument("--stopped", dest="state", action="append_const",
-                    const="STOPPED", help=_("list only stopped containers"))
-
-parser.add_argument("-f", "--fancy", action="store_true",
-                    help=_("use fancy output"))
-
-parser.add_argument("-F", "--fancy-format", type=str,
-                    default=",".join(DEFAULT_FIELDS),
-                    help=_("comma separated list of fields to show"))
-
-parser.add_argument("-g", "--groups", type=str, action="append",
-                    metavar="GROUPS",
-                    help=_("groups (comma separated) the container must "
-                           "be a member of"))
-
-parser.add_argument("--nesting", dest="nesting", action="store_true",
-                    help=_("show nested containers"))
-
-parser.add_argument("filter", metavar='FILTER', type=str, nargs="?",
-                    help=_("regexp to be applied on the container list"))
-
-parser.add_argument("--version", action="version", version=lxc.version)
-
-args = parser.parse_args()
-
-# --active is the same as --running --frozen
-if args.active:
-    if not args.state:
-        args.state = []
-    args.state += ["RUNNING", "FROZEN", "UNKNOWN"]
-
-# If the output is piped, default to --one
-if not sys.stdout.isatty():
-    args.one = True
-
-# Turn args.fancy_format into a list
-args.fancy_format = args.fancy_format.strip().split(",")
-
-if set(args.fancy_format) - set(FIELDS):
-    parser.error(_("Invalid field(s): %s" %
-                 ", ".join(list(set(args.fancy_format) - set(FIELDS)))))
-
-# Basic checks
-## Check for setns
-SUPPORT_SETNS = os.path.exists("/proc/self/ns")
-SUPPORT_SETNS_NET = False
-SUPPORT_SETNS_PID = False
-if SUPPORT_SETNS:
-    SUPPORT_SETNS_NET = os.path.exists("/proc/self/ns/net")
-    SUPPORT_SETNS_PID = os.path.exists("/proc/self/ns/pid")
-
-## Nesting requires setns to pid and net ns
-if args.nesting:
-    if not SUPPORT_SETNS:
-        parser.error(_("Showing nested containers requires setns support "
-                       "which your kernel doesn't support."))
-
-    if not SUPPORT_SETNS_NET:
-        parser.error(_("Showing nested containers requires setns to the "
-                       "network namespace which your kernel doesn't support."))
-
-    if not SUPPORT_SETNS_PID:
-        parser.error(_("Showing nested containers requires setns to the "
-                       "PID namespace which your kernel doesn't support."))
-
-# Set the actual lxcpath value
-if not args.lxcpath:
-    args.lxcpath = lxc.default_config_path
-
-
-# List of containers, stored as dictionaries
-def get_containers(fd=None, base="/", root=False):
-    containers = []
-
-    paths = [args.lxcpath]
-
-    if not root:
-        paths.append(get_root_path(base))
-
-    # Generate a unique list of valid paths
-    paths = set([os.path.normpath("%s/%s" % (base, path)) for path in paths])
-
-    for path in paths:
-        if not os.access(path, os.R_OK):
-            continue
-
-        for container_name in lxc.list_containers(config_path=path):
-            entry = {}
-            entry['name'] = container_name
-
-            # Apply filter
-            if root and args.filter and \
-               not re.match(args.filter, container_name):
-                continue
-
-            # Return before grabbing the object (non-root)
-            if not args.state and not args.fancy and not args.nesting \
-                    and not args.groups:
-                containers.append(entry)
-                continue
-
-            try:
-                container = lxc.Container(container_name, path)
-            except:
-                continue
-
-            if args.groups or "autostart" in args.fancy_format \
-                    or "groups" in args.fancy_format:
-                try:
-                    groups = container.get_config_item("lxc.group")
-                except KeyError:
-                    groups = []
-
-            if args.groups:
-                set_has = set(groups)
-
-                for group in args.groups:
-                    set_must = set(group.split(","))
-                    if not set_must - set_has:
-                        break
-                else:
-                    continue
-
-            if container.controllable:
-                state = container.state
-            else:
-                state = 'UNKNOWN'
-
-            # Filter by status
-            if args.state and state not in args.state:
-                continue
-
-            # Nothing more is needed if we're not printing some fancy output
-            if not args.fancy and not args.nesting:
-                containers.append(entry)
-                continue
-
-            # Some extra field we may want
-            if 'state' in args.fancy_format:
-                entry['state'] = state
-
-            if 'pid' in args.fancy_format:
-                entry['pid'] = "-"
-                if state == 'UNKNOWN':
-                    entry['pid'] = state
-                elif container.init_pid != -1:
-                    entry['pid'] = str(container.init_pid)
-
-            if 'groups' in args.fancy_format:
-                entry['groups'] = "-"
-                if len(groups) > 0:
-                    entry['groups'] = ", ".join(groups)
-
-            if 'autostart' in args.fancy_format:
-                entry['autostart'] = "NO"
-                try:
-                    if container.get_config_item("lxc.start.auto") == "1":
-                        if len(groups) > 0:
-                            entry['autostart'] = "BY-GROUP"
-                        else:
-                            entry['autostart'] = "YES"
-                except KeyError:
-                    pass
-
-            if 'memory' in args.fancy_format or \
-               'ram' in args.fancy_format or \
-               'swap' in args.fancy_format:
-
-                if container.running:
-                    try:
-                        memory_ram = int(container.get_cgroup_item(
-                            "memory.usage_in_bytes"))
-                    except:
-                        memory_ram = 0
-
-                    try:
-                        memory_swap = int(container.get_cgroup_item(
-                            "memory.memsw.usage_in_bytes")) - memory_ram
-                    except:
-                        memory_swap = 0
-                else:
-                    memory_ram = 0
-                    memory_swap = 0
-
-                memory_total = memory_ram + memory_swap
-
-            if 'memory' in args.fancy_format:
-                if container.running:
-                    entry['memory'] = "%sMB" % round(memory_total / 1048576, 2)
-                else:
-                    entry['memory'] = "-"
-
-            if 'ram' in args.fancy_format:
-                if container.running:
-                    entry['ram'] = "%sMB" % round(memory_ram / 1048576, 2)
-                else:
-                    entry['ram'] = "-"
-
-            if 'swap' in args.fancy_format:
-                if container.running:
-                    entry['swap'] = "%sMB" % round(memory_swap / 1048576, 2)
-                else:
-                    entry['swap'] = "-"
-
-            # Get the IPs
-            for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
-                if protocol in args.fancy_format:
-                    entry[protocol] = "-"
-
-                    if state == 'UNKNOWN':
-                        entry[protocol] = state
-                        continue
-
-                    if container.running:
-                        if not SUPPORT_SETNS_NET:
-                            entry[protocol] = 'UNKNOWN'
-                            continue
-
-                        ips = container.get_ips(family=family)
-                        if ips:
-                            entry[protocol] = ", ".join(ips)
-
-            # Get the interfaces
-            if 'interfaces' in args.fancy_format:
-                entry['interfaces'] = "-"
-
-                if state == 'UNKNOWN' or (container.running and
-                                          not SUPPORT_SETNS_NET):
-                    entry['interfaces'] = "UNKNOWN"
-                elif container.running:
-                    interfaces = container.get_interfaces()
-                    if interfaces:
-                        entry['interfaces'] = ", ".join(interfaces)
-
-            # Nested containers
-            if args.nesting:
-                if container.running:
-                    # Recursive call in container namespace
-                    temp_fd, temp_file = tempfile.mkstemp()
-                    os.remove(temp_file)
-
-                    container.attach_wait(get_containers, temp_fd)
-
-                    json_file = os.fdopen(temp_fd, "r")
-                    json_file.seek(0)
-
-                    try:
-                        sub_containers = json.loads(json_file.read())
-                    except:
-                        sub_containers = []
-
-                    json_file.close()
-                else:
-                    def clear_lock():
-                        try:
-                            lock_path = "%s/lock/lxc/%s/%s" % (RUNTIME_PATH,
-                                                               path,
-                                                               entry['name'])
-                            if os.path.exists(lock_path):
-                                if os.path.isdir(lock_path):
-                                    shutil.rmtree(lock_path)
-                                else:
-                                    os.remove(lock_path)
-                        except:
-                            pass
-
-                    clear_lock()
-
-                    # Recursive call using container rootfs
-                    sub_containers = get_containers(
-                        base="%s/%s" % (
-                            base, container.get_config_item("lxc.rootfs")))
-
-                    clear_lock()
-
-                for sub in sub_containers:
-                    if 'nesting_parent' not in sub:
-                        sub['nesting_parent'] = []
-                    sub['nesting_parent'].insert(0, entry['name'])
-                    sub['nesting_real_name'] = sub.get('nesting_real_name',
-                                                       sub['name'])
-                    sub['name'] = "%s/%s" % (entry['name'], sub['name'])
-                    containers.append(sub)
-
-            # Append the container
-            containers.append(entry)
-
-    if fd:
-        json_file = os.fdopen(fd, "w+")
-        json_file.write(json.dumps(containers))
-        return
-
-    return containers
-
-containers = get_containers(root=True)
-
-# Print the list
-## Standard list with one entry per line
-if not args.fancy and args.one:
-    for container in sorted(containers,
-                            key=lambda container: container['name']):
-        print(container['name'])
-    sys.exit(0)
-
-## Standard list with multiple entries per line
-if not args.fancy and not args.one:
-    # Get the longest name and extra simple list
-    field_maxlength = 0
-    container_names = []
-    for container in containers:
-        if len(container['name']) > field_maxlength:
-            field_maxlength = len(container['name'])
-        container_names.append(container['name'])
-
-    # Figure out how many we can put per line
-    width = get_terminal_size()[0]
-
-    entries = int(width / (field_maxlength + 2))
-    if entries == 0:
-        entries = 1
-
-    for line in batch(sorted(container_names), entries):
-        line_format = ""
-        for index in range(len(line)):
-            line_format += "{line[%s]:%s}" % (index, field_maxlength + 2)
-
-        print(line_format.format(line=line))
-
-## Fancy listing
-if args.fancy:
-    field_maxlength = {}
-
-    # Get the maximum length per field
-    for field in args.fancy_format:
-        field_maxlength[field] = len(field)
-
-    for container in containers:
-        for field in args.fancy_format:
-            if field == 'name' and 'nesting_real_name' in container:
-                fieldlen = len(" " * ((len(container['nesting_parent']) - 1)
-                               * 4) + " \_ " + container['nesting_real_name'])
-                if fieldlen > field_maxlength[field]:
-                    field_maxlength[field] = fieldlen
-            elif len(container[field]) > field_maxlength[field]:
-                field_maxlength[field] = len(container[field])
-
-    # Generate the line format string based on the maximum length and
-    # a 2 character padding
-    line_format = ""
-    index = 0
-    for field in args.fancy_format:
-        line_format += "{fields[%s]:%s}" % (index, field_maxlength[field] + 2)
-        index += 1
-
-    # Get the line length minus the padding of the last field
-    line_length = -2
-    for field in field_maxlength:
-        line_length += field_maxlength[field] + 2
-
-    # Print header
-    print(line_format.format(fields=[header.upper()
-                                     for header in args.fancy_format]))
-    print("-" * line_length)
-
-    # Print the entries
-    for container in sorted(containers,
-                            key=lambda container: container['name']):
-        fields = []
-        for field in args.fancy_format:
-            if field == 'name' and 'nesting_real_name' in container:
-                prefix = " " * ((len(container['nesting_parent']) - 1) * 4)
-                fields.append(prefix + " \_ " + container['nesting_real_name'])
-            else:
-                fields.append(container[field])
-
-        print(line_format.format(fields=fields))
index e649419..7e0c8ea 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 #
 # lxc-start-ephemeral: Start a copy of a container using an overlay
 #
@@ -36,8 +36,14 @@ import tempfile
 _ = gettext.gettext
 gettext.textdomain("lxc-start-ephemeral")
 
-
 # Other functions
+
+
+def printstderr(*args):
+    print("lxc-start-ephemeral is deprecated in favor of lxc-copy\n",
+          *args, file=sys.stderr)
+
+
 def randomMAC():
     import random
 
@@ -61,6 +67,9 @@ def get_rundir():
     raise Exception("Unable to find a runtime directory")
 
 
+# Inform that lxc-start-ephemeral is deprecated
+printstderr()
+
 # Begin parsing the command line
 parser = argparse.ArgumentParser(description=_(
                                  "LXC: Start an ephemeral container"),
@@ -84,7 +93,8 @@ parser.add_argument("--name", "-n", type=str,
                     help=_("name of the target container"))
 
 parser.add_argument("--bdir", "-b", type=str, action="append", default=[],
-                    help=_("directory to bind mount into container"))
+                    help=_("directory to bind mount into container, "
+                           "either --bdir=/src-path or --bdir=/src-path:/dst-path"))
 
 parser.add_argument("--cdir", "-c", type=str, action="append", default=[],
                     help=_("directory to cow mount into container"))
@@ -119,11 +129,11 @@ parser.add_argument("--version", action="version", version=lxc.version)
 
 args = parser.parse_args()
 
-## Check that -d and CMD aren't used at the same time
+# Check that -d and CMD aren't used at the same time
 if args.command and args.daemon:
     parser.error(_("You can't use -d and a command at the same time."))
 
-## Check that -k isn't used with -s tmpfs
+# Check that -k isn't used with -s tmpfs
 if not args.storage_type:
     if args.keep_data:
         args.storage_type = "dir"
@@ -275,12 +285,18 @@ LXC_NAME="%s"
         count += 1
 
     for entry in args.bdir:
-        if not os.path.exists(entry):
+        if ':' in entry:
+            src_path, dst_path = entry.split(":")
+        else:
+            src_path = entry
+            dst_path = os.path.abspath(entry)
+
+        if not os.path.exists(src_path):
             print(_("Path '%s' doesn't exist, won't be bind-mounted.") %
-                  entry)
+                  src_path)
         else:
-            src_path = os.path.abspath(entry)
-            dst_path = "%s/rootfs/%s" % (dest_path, os.path.abspath(entry))
+            src_path = os.path.abspath(src_path)
+            dst_path = "%s/rootfs/%s" % (dest_path, dst_path)
             fd.write("mkdir -p %s\nmount -n --bind %s %s\n" % (
                      dst_path, src_path, dst_path))
 
@@ -298,16 +314,8 @@ touch $LXC_DIR/configured
 dest.set_config_item("lxc.hook.pre-mount",
                      os.path.join(dest_path, "pre-mount"))
 
-# Generate post-stop script
 if not args.keep_data:
-    with open(os.path.join(dest_path, "post-stop"), "w+") as fd:
-        os.fchmod(fd.fileno(), 0o755)
-        fd.write("""#!/bin/sh
-[ -d "%s" ] && rm -Rf "%s"
-""" % (dest_path, dest_path))
-
-    dest.set_config_item("lxc.hook.post-stop",
-                         os.path.join(dest_path, "post-stop"))
+    dest.set_config_item("lxc.ephemeral", "1")
 
 dest.save_config()
 
index 1c24349..ffcd3d1 100644 (file)
 
 #define _GNU_SOURCE
 #include <assert.h>
-#include <sys/wait.h>
-#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <lxc/lxccontainer.h>
 
 #include "attach.h"
 #include "arguments.h"
+#include "caps.h"
 #include "config.h"
 #include "confile.h"
-#include "namespace.h"
-#include "caps.h"
+#include "console.h"
 #include "log.h"
+#include "list.h"
+#include "mainloop.h"
 #include "utils.h"
 
+#if HAVE_PTY_H
+#include <pty.h>
+#else
+#include <../include/openpty.h>
+#endif
+
 lxc_log_define(lxc_attach_ui, lxc);
 
 static const struct option my_longopts[] = {
@@ -186,20 +202,185 @@ Options :\n\
        .checker  = NULL,
 };
 
+struct wrapargs {
+       lxc_attach_options_t *options;
+       lxc_attach_command_t *command;
+       struct lxc_console *console;
+       int ptyfd;
+};
+
+/* Minimalistic login_tty() implementation. */
+static int login_pty(int fd)
+{
+       setsid();
+       if (ioctl(fd, TIOCSCTTY, NULL) < 0)
+               return -1;
+       if (lxc_console_set_stdfds(fd) < 0)
+               return -1;
+       if (fd > STDERR_FILENO)
+               close(fd);
+       return 0;
+}
+
+static int get_pty_on_host_callback(void *p)
+{
+       struct wrapargs *wrap = p;
+
+       close(wrap->console->master);
+       if (login_pty(wrap->console->slave) < 0)
+               return -1;
+
+       if (wrap->command->program)
+               lxc_attach_run_command(wrap->command);
+       else
+               lxc_attach_run_shell(NULL);
+       return -1;
+}
+
+static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
+{
+       int ret = -1;
+       struct wrapargs *args = wrap;
+       struct lxc_epoll_descr descr;
+       struct lxc_conf *conf;
+       struct lxc_tty_state *ts;
+
+       INFO("Trying to allocate a pty on the host");
+
+       if (!isatty(args->ptyfd)) {
+               ERROR("stdin is not a tty");
+               return -1;
+       }
+
+       conf = c->lxc_conf;
+       free(conf->console.log_path);
+       conf->console.log_path = NULL;
+
+       /* In the case of lxc-attach our peer pty will always be the current
+        * controlling terminal. We clear whatever was set by the user for
+        * lxc.console.path here and set it to "/dev/tty". Doing this will (a)
+        * prevent segfaults when the container has been setup with
+        * lxc.console = none and (b) provide an easy way to ensure that we
+        * always do the correct thing. strdup() must be used since console.path
+        * is free()ed when we call lxc_container_put(). */
+       free(conf->console.path);
+       conf->console.path = NULL;
+       conf->console.path = strdup("/dev/tty");
+       if (!conf->console.path)
+               return -1;
+
+       /* Create pty on the host. */
+       if (lxc_console_create(conf) < 0)
+               return -1;
+       ts = conf->console.tty_state;
+       /*
+        * We need to make sure that the ouput that is produced inside the
+        * container is received on the host. Suppose we want to run
+        *
+        *      lxc-attach -n a -- /bin/sh -c 'hostname >&2' > /dev/null
+        *
+        * This command produces output on stderr inside the container. On the
+        * host we close stdout by redirecting it to /dev/null. But stderr is,
+        * as expected, still connected to a tty. We receive the output produced
+        * on stderr in the container on stderr on the host.
+        *
+        * For the command
+        *
+        *      lxc-attach -n a -- /bin/sh -c 'hostname >&2' 2> /dev/null
+        *
+        * the logic is analogous but because we now have closed stderr on the
+        * host no output will be received.
+        *
+        * Finally, imagine a more complicated case
+        *
+        *      lxc-attach -n a -- /bin/sh -c 'echo OUT; echo ERR >&2' > /tmp/out 2> /tmp/err
+        *
+        * Here, we produce output in the container on stdout and stderr. On the
+        * host we redirect stdout and stderr to files. Because of that stdout
+        * and stderr are not dup2()ed. Thus, they are not connected to a pty
+        * and output on stdout and stderr is redirected to the corresponding
+        * files as expected.
+        */
+       if (!isatty(STDOUT_FILENO) && isatty(STDERR_FILENO))
+               ts->stdoutfd = STDERR_FILENO;
+       else
+               ts->stdoutfd = STDOUT_FILENO;
+
+       conf->console.descr = &descr;
+
+       /* Shift ttys to container. */
+       if (ttys_shift_ids(conf) < 0) {
+               ERROR("Failed to shift tty into container");
+               goto err1;
+       }
+
+       /* Send wrapper function on its way. */
+       wrap->console = &conf->console;
+       if (c->attach(c, get_pty_on_host_callback, wrap, wrap->options, pid) < 0)
+               goto err1;
+       close(conf->console.slave); /* Close slave side. */
+
+       ret = lxc_mainloop_open(&descr);
+       if (ret) {
+               ERROR("failed to create mainloop");
+               goto err2;
+       }
+
+       /* Register sigwinch handler in mainloop. */
+       ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
+                       lxc_console_cb_sigwinch_fd, ts);
+       if (ret) {
+               ERROR("failed to add handler for SIGWINCH fd");
+               goto err3;
+       }
+
+       /* Register i/o callbacks in mainloop. */
+       ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
+                       lxc_console_cb_tty_stdin, ts);
+       if (ret) {
+               ERROR("failed to add handler for stdinfd");
+               goto err3;
+       }
+
+       ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
+                       lxc_console_cb_tty_master, ts);
+       if (ret) {
+               ERROR("failed to add handler for masterfd");
+               goto err3;
+       }
+
+       ret = lxc_mainloop(&descr, -1);
+       if (ret) {
+               ERROR("mainloop returned an error");
+               goto err3;
+       }
+       ret = 0;
+
+err3:
+       lxc_mainloop_close(&descr);
+err2:
+       lxc_console_sigwinch_fini(ts);
+err1:
+       lxc_console_delete(&conf->console);
+
+       return ret;
+}
+
 int main(int argc, char *argv[])
 {
-       int ret;
+       int ret = -1;
+       int wexit = 0;
        pid_t pid;
        lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
-       lxc_attach_command_t command;
+       lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
 
        ret = lxc_caps_init();
        if (ret)
-               return 1;
+               exit(EXIT_FAILURE);
 
        ret = lxc_arguments_parse(&my_args, argc, argv);
        if (ret)
-               return 1;
+               exit(EXIT_FAILURE);
 
        if (!my_args.log_file)
                my_args.log_file = "none";
@@ -207,9 +388,33 @@ int main(int argc, char *argv[])
        ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
                           my_args.progname, my_args.quiet, my_args.lxcpath[0]);
        if (ret)
-               return 1;
+               exit(EXIT_FAILURE);
        lxc_log_options_no_override();
 
+       if (geteuid()) {
+               if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+                       if (!my_args.quiet)
+                               fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+       if (!c)
+               exit(EXIT_FAILURE);
+
+       if (!c->may_control(c)) {
+               fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+               lxc_container_put(c);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!c->is_defined(c)) {
+               fprintf(stderr, "Error: container %s is not defined\n", c->name);
+               lxc_container_put(c);
+               exit(EXIT_FAILURE);
+       }
+
        if (remount_sys_proc)
                attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
        if (elevated_privileges)
@@ -220,23 +425,42 @@ int main(int argc, char *argv[])
        attach_options.extra_env_vars = extra_env;
        attach_options.extra_keep_env = extra_keep;
 
-       if (my_args.argc) {
+       if (my_args.argc > 0) {
                command.program = my_args.argv[0];
                command.argv = (char**)my_args.argv;
-               ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_command, &command, &attach_options, &pid);
+       }
+
+       if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO)) {
+               struct wrapargs wrap = (struct wrapargs){
+                       .command = &command,
+                       .options = &attach_options
+               };
+               if (isatty(STDIN_FILENO))
+                       wrap.ptyfd = STDIN_FILENO;
+               else if (isatty(STDOUT_FILENO))
+                       wrap.ptyfd = STDOUT_FILENO;
+               else if (isatty(STDERR_FILENO))
+                       wrap.ptyfd = STDERR_FILENO;
+               ret = get_pty_on_host(c, &wrap, &pid);
        } else {
-               ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_shell, NULL, &attach_options, &pid);
+               if (command.program)
+                       ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
+               else
+                       ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
        }
 
        if (ret < 0)
-               return 1;
+               goto out;
 
        ret = lxc_wait_for_pid_status(pid);
        if (ret < 0)
-               return 1;
+               goto out;
 
        if (WIFEXITED(ret))
-               return WEXITSTATUS(ret);
-
-       return 1;
+               wexit = WEXITSTATUS(ret);
+out:
+       lxc_container_put(c);
+       if (ret >= 0)
+               exit(wexit);
+       exit(EXIT_FAILURE);
 }
index 1e48f94..eed0f5f 100644 (file)
@@ -306,7 +306,7 @@ static int cmporder(const void *p1, const void *p2) {
        if (c1_order == c2_order)
                return strcmp(c1->name, c2->name);
        else
-               return (c1_order - c2_order) * -1;
+               return (c1_order - c2_order);
 }
 
 static int toss_list( struct lxc_list *c_groups_list ) {
index 3e5de4a..7130245 100644 (file)
@@ -121,7 +121,7 @@ Options :\n\
        .checker   = my_checker,
 };
 
-bool checkpoint(struct lxc_container *c)
+static bool checkpoint(struct lxc_container *c)
 {
        bool ret;
 
@@ -142,7 +142,7 @@ bool checkpoint(struct lxc_container *c)
        return true;
 }
 
-bool restore_finalize(struct lxc_container *c)
+static bool restore_finalize(struct lxc_container *c)
 {
        bool ret = c->restore(c, checkpoint_dir, verbose);
        if (!ret) {
@@ -153,7 +153,7 @@ bool restore_finalize(struct lxc_container *c)
        return ret;
 }
 
-bool restore(struct lxc_container *c)
+static bool restore(struct lxc_container *c)
 {
        if (c->is_running(c)) {
                fprintf(stderr, "%s is running, not restoring.\n", my_args.name);
index df1b5ef..6bd2226 100644 (file)
@@ -65,7 +65,7 @@ static uint64_t get_fssize(char *s)
        else if (*end == 't' || *end == 'T')
                ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
        else
-       {               
+       {
                fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
                return 0;
        }
@@ -88,6 +88,7 @@ static void usage(const char *me)
        printf("  -M: Keep macaddr - do not choose a random new mac address\n");
        printf("  -p: use container orig from custom lxcpath\n");
        printf("  -P: create container new in custom lxcpath\n");
+       printf("  -R: rename existing container\n");
        exit(1);
 }
 
@@ -98,6 +99,7 @@ static struct option options[] = {
        { "orig", required_argument, 0, 'o'},
        { "new", required_argument, 0, 'n'},
        { "vgname", required_argument, 0, 'v'},
+       { "rename", no_argument, 0, 'R'},
        { "keepname", no_argument, 0, 'K'},
        { "keepmac", no_argument, 0, 'M'},
        { "lxcpath", required_argument, 0, 'p'},
@@ -110,19 +112,22 @@ static struct option options[] = {
 int main(int argc, char *argv[])
 {
        struct lxc_container *c1 = NULL, *c2 = NULL;
-       int snapshot = 0, keepname = 0, keepmac = 0;
+       int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
        int flags = 0, option_index;
        uint64_t newsize = 0;
        char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
        char *orig = NULL, *new = NULL, *vgname = NULL;
        char **args = NULL;
        int c;
+       bool ret;
+
+       fprintf(stderr, "lxc-clone is deprecated in favor of lxc-copy.\n\n");
 
        if (argc < 3)
                usage(argv[0]);
 
        while (1) {
-               c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:t:h", options, &option_index);
+               c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
                if (c == -1)
                        break;
                switch (c) {
@@ -136,6 +141,7 @@ int main(int argc, char *argv[])
                case 'M': keepmac = 1; break;
                case 'p': lxcpath = optarg; break;
                case 'P': newpath = optarg; break;
+               case 'R': rename = 1; break;
                case 't': fstype = optarg; break;
                case 'h': usage(argv[0]);
                default: break;
@@ -171,28 +177,41 @@ int main(int argc, char *argv[])
 
        c1 = lxc_container_new(orig, lxcpath);
        if (!c1)
-               exit(1);
+               exit(EXIT_FAILURE);
 
        if (!c1->may_control(c1)) {
                fprintf(stderr, "Insufficent privileges to control %s\n", orig);
                lxc_container_put(c1);
-               return 1;
+               exit(EXIT_FAILURE);
        }
 
        if (!c1->is_defined(c1)) {
                fprintf(stderr, "Error: container %s is not defined\n", orig);
                lxc_container_put(c1);
-               exit(1);
+               exit(EXIT_FAILURE);
        }
-       c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize, args);
-       if (c2 == NULL) {
-               lxc_container_put(c1);
-               fprintf(stderr, "clone failed\n");
-               exit(1);
+       if (rename) {
+               ret = c1->rename(c1, new);
+               if (!ret) {
+                       fprintf(stderr,
+                               "Error: Renaming container %s to %s failed\n",
+                               c1->name, new);
+                       lxc_container_put(c1);
+                       exit(EXIT_FAILURE);
+               }
+       } else {
+               c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
+                              args);
+               if (c2 == NULL) {
+                       lxc_container_put(c1);
+                       fprintf(stderr, "clone failed\n");
+                       exit(EXIT_FAILURE);
+               }
+               printf("Created container %s as %s of %s\n", new,
+                      snapshot ? "snapshot" : "copy", orig);
+               lxc_container_put(c2);
        }
-       printf("Created container %s as %s of %s\n", new,
-               snapshot ? "snapshot" : "copy", orig);
        lxc_container_put(c1);
-       lxc_container_put(c2);
-       return(0);
+
+       exit(EXIT_SUCCESS);
 }
diff --git a/src/lxc/lxc_copy.c b/src/lxc/lxc_copy.c
new file mode 100644 (file)
index 0000000..e424e65
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ *
+ * Copyright © 2015 Christian Brauner <christian.brauner@mailbox.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "attach.h"
+#include "log.h"
+#include "confile.h"
+#include "arguments.h"
+#include "lxc.h"
+#include "conf.h"
+#include "state.h"
+#include "utils.h"
+#include "bdev/bdev.h"
+
+#ifndef HAVE_GETSUBOPT
+#include <../include/getsubopt.h>
+#endif
+
+lxc_log_define(lxc_copy_ui, lxc);
+
+enum mnttype {
+       LXC_MNT_BIND,
+       LXC_MNT_AUFS,
+       LXC_MNT_OVL,
+};
+
+struct mnts {
+       enum mnttype mnt_type;
+       char *src;
+       char *dest;
+       char *options;
+       char *upper;
+       char *workdir;
+       char *lower;
+};
+
+static unsigned int mnt_table_size = 0;
+static struct mnts *mnt_table = NULL;
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
+
+static const struct option my_longopts[] = {
+       { "newname", required_argument, 0, 'N'},
+       { "newpath", required_argument, 0, 'p'},
+       { "rename", no_argument, 0, 'R'},
+       { "snapshot", no_argument, 0, 's'},
+       { "foreground", no_argument, 0, 'F'},
+       { "daemon", no_argument, 0, 'd'},
+       { "ephemeral", no_argument, 0, 'e'},
+       { "mount", required_argument, 0, 'm'},
+       { "backingstore", required_argument, 0, 'B'},
+       { "fssize", required_argument, 0, 'L'},
+       { "keepdata", no_argument, 0, 'D'},
+       { "keepname", no_argument, 0, 'K'},
+       { "keepmac", no_argument, 0, 'M'},
+       LXC_COMMON_OPTIONS
+};
+
+/* mount keys */
+static char *const keys[] = {
+       [LXC_MNT_BIND] = "bind",
+       [LXC_MNT_AUFS] = "aufs",
+       [LXC_MNT_OVL] = "overlay",
+       NULL
+};
+
+static struct lxc_arguments my_args = {
+       .progname = "lxc-copy",
+       .help = "\n\
+--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]] -- hook options\n\
+--name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,aufs,overlay}=/src:/dest] -- hook options\n\
+--name=NAME [-P lxcpath] -N newname -R\n\
+\n\
+lxc-copy clone a container\n\
+\n\
+Options :\n\
+  -n, --name=NAME           NAME of the container\n\
+  -N, --newname=NEWNAME     NEWNAME for the restored container\n\
+  -p, --newpath=NEWPATH     NEWPATH for the container to be stored\n\
+  -R, --rename             rename container\n\
+  -s, --snapshot           create snapshot instead of clone\n\
+  -F, --foreground         start with current tty attached to /dev/console\n\
+  -d, --daemon             daemonize the container (default)\n\
+  -e, --ephemeral          start ephemeral container\n\
+  -m, --mount              directory to mount into container, either \n\
+                           {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
+  -B, --backingstorage=TYPE backingstorage type for the container\n\
+  -L, --fssize             size of the new block device for block device containers\n\
+  -D, --keedata                    pass together with -e start a persistent snapshot \n\
+  -K, --keepname           keep the hostname of the original container\n\
+  --  hook options         arguments passed to the hook program\n\
+  -M, --keepmac                    keep the MAC address of the original container\n",
+       .options = my_longopts,
+       .parser = my_parser,
+       .task = CLONE,
+       .daemonize = 1,
+       .quiet = false,
+};
+
+static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
+                           enum mnttype type);
+static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num,
+                           struct lxc_arguments *arg);
+static char *construct_path(char *path, bool as_prefix);
+static char *set_mnt_entry(struct mnts *m);
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,
+                   int flags, char *bdevtype, uint64_t fssize, enum task task,
+                   char **args);
+static int do_clone_ephemeral(struct lxc_container *c,
+                             struct lxc_arguments *arg, char **args,
+                             int flags);
+static int do_clone_rename(struct lxc_container *c, char *newname);
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,
+                        char **args);
+static void free_mnts(void);
+static uint64_t get_fssize(char *s);
+static int parse_mntsubopts(char *subopts, char *const *keys,
+                           char *mntparameters);
+static int parse_aufs_mnt(char *mntstring, enum mnttype type);
+static int parse_bind_mnt(char *mntstring, enum mnttype type);
+static int parse_ovl_mnt(char *mntstring, enum mnttype type);
+
+int main(int argc, char *argv[])
+{
+       struct lxc_container *c;
+       int flags = 0;
+       int ret = EXIT_FAILURE;
+
+       if (lxc_arguments_parse(&my_args, argc, argv))
+               exit(ret);
+
+       if (!my_args.log_file)
+               my_args.log_file = "none";
+
+       if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+                        my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+               exit(ret);
+       lxc_log_options_no_override();
+
+       if (geteuid()) {
+               if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+                       if (!my_args.quiet)
+                               fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+                       exit(ret);
+               }
+       }
+
+       if (!my_args.newname && !(my_args.task == DESTROY)) {
+               if (!my_args.quiet)
+                       printf("Error: You must provide a NEWNAME for the clone.\n");
+               exit(ret);
+       }
+
+       if (my_args.task == SNAP || my_args.task == DESTROY)
+               flags |= LXC_CLONE_SNAPSHOT;
+       if (my_args.keepname)
+               flags |= LXC_CLONE_KEEPNAME;
+       if (my_args.keepmac)
+               flags |= LXC_CLONE_KEEPMACADDR;
+
+       if (!my_args.newpath)
+               my_args.newpath = (char *)my_args.lxcpath[0];
+
+       c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+       if (!c)
+               exit(ret);
+
+       if (!c->may_control(c)) {
+               if (!my_args.quiet)
+                       fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+               goto out;
+       }
+
+       if (!c->is_defined(c)) {
+               if (!my_args.quiet)
+                       fprintf(stderr, "Error: container %s is not defined\n", c->name);
+               goto out;
+       }
+
+       ret = do_clone_task(c, my_args.task, flags, &argv[optind]);
+
+out:
+       lxc_container_put(c);
+
+       if (ret == 0)
+               exit(EXIT_SUCCESS);
+       exit(EXIT_FAILURE);
+}
+
+static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype type)
+{
+       struct mnts *m, *n;
+
+       n = realloc(*mnts, (*num + 1) * sizeof(struct mnts));
+       if (!n)
+               return NULL;
+
+       *mnts = n;
+       m = *mnts + *num;
+       (*num)++;
+
+       *m = (struct mnts) {.mnt_type = type};
+
+       return m;
+}
+
+static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
+{
+       char upperdir[MAXPATHLEN];
+       char workdir[MAXPATHLEN];
+       unsigned int i;
+       int ret;
+       struct mnts *m = NULL;
+
+       for (i = 0, m = mnts; i < num; i++, m++) {
+               if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
+                       ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
+                                       arg->newpath, arg->newname);
+                       if (ret < 0 || ret >= MAXPATHLEN)
+                               return -1;
+                       if (!mkdtemp(upperdir))
+                               return -1;
+                       m->upper = strdup(upperdir);
+                       if (!m->upper)
+                               return -1;
+               }
+
+               if (m->mnt_type == LXC_MNT_OVL) {
+                       ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
+                                       arg->newpath, arg->newname);
+                       if (ret < 0 || ret >= MAXPATHLEN)
+                               return -1;
+                       if (!mkdtemp(workdir))
+                               return -1;
+                       m->workdir = strdup(workdir);
+                       if (!m->workdir)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+static char *construct_path(char *path, bool as_prefix)
+{
+       char **components = NULL;
+       char *cleanpath = NULL;
+
+       components = lxc_normalize_path(path);
+       if (!components)
+               return NULL;
+
+       cleanpath = lxc_string_join("/", (const char **)components, as_prefix);
+       lxc_free_array((void **)components, free);
+
+       return cleanpath;
+}
+
+static char *set_mnt_entry(struct mnts *m)
+{
+       char *mntentry = NULL;
+       int ret = 0;
+       size_t len = 0;
+
+       if (m->mnt_type == LXC_MNT_AUFS) {
+               len = strlen("  aufs br==rw:=ro,xino=,create=dir") +
+                     2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
+                     strlen(m->workdir) + 1;
+
+               mntentry = malloc(len);
+               if (!mntentry)
+                       goto err;
+
+               ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
+                              m->src, m->dest, m->upper, m->src, m->workdir);
+               if (ret < 0 || (size_t)ret >= len)
+                       goto err;
+       } else if (m->mnt_type == LXC_MNT_OVL) {
+               len = strlen("  overlay lowerdir=,upperdir=,workdir=,create=dir") +
+                     2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
+                     strlen(m->workdir) + 1;
+
+               mntentry = malloc(len);
+               if (!mntentry)
+                       goto err;
+
+               ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",
+                               m->src, m->dest, m->src, m->upper, m->workdir);
+               if (ret < 0 || (size_t)ret >= len)
+                       goto err;
+       } else if (m->mnt_type == LXC_MNT_BIND) {
+               len = strlen("  none bind,optional,, 0 0") +
+                     strlen(is_dir(m->src) ? "create=dir" : "create=file") +
+                     strlen(m->src) + strlen(m->dest) + strlen(m->options) + 1;
+
+               mntentry = malloc(len);
+               if (!mntentry)
+                       goto err;
+
+               ret = snprintf(mntentry, len, "%s %s none bind,optional,%s,%s 0 0",
+                               m->src, m->dest, m->options,
+                               is_dir(m->src) ? "create=dir" : "create=file");
+               if (ret < 0 || (size_t)ret >= len)
+                       goto err;
+       }
+
+       return mntentry;
+
+err:
+       free(mntentry);
+       return NULL;
+}
+
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,
+                   int flags, char *bdevtype, uint64_t fssize, enum task task,
+                   char **args)
+{
+       struct lxc_container *clone;
+
+       clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
+                        args);
+       if (!clone) {
+               if (!my_args.quiet)
+                       fprintf(stderr, "clone failed\n");
+               return -1;
+       }
+
+       INFO("Created %s as %s of %s\n", newname, task ? "snapshot" : "copy", c->name);
+
+       lxc_container_put(clone);
+
+       return 0;
+}
+
+static int do_clone_ephemeral(struct lxc_container *c,
+               struct lxc_arguments *arg, char **args, int flags)
+{
+       char randname[MAXPATHLEN];
+       unsigned int i;
+       int ret = 0;
+       bool bret = true, started = false;
+       struct lxc_container *clone;
+
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+       attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
+
+       if (!arg->newname) {
+               ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       return -1;
+               if (!mkdtemp(randname))
+                       return -1;
+               if (chmod(randname, 0770) < 0) {
+                       remove(randname);
+                       return -1;
+               }
+               arg->newname = randname + strlen(arg->newpath) + 1;
+       }
+
+       clone = c->clone(c, arg->newname, arg->newpath, flags,
+                        arg->bdevtype, NULL, arg->fssize, args);
+       if (!clone)
+               return -1;
+
+       if (!arg->keepdata)
+               if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
+                       goto destroy_and_put;
+
+       /* allocate and create random upper- and workdirs for overlay mounts */
+       if (mk_rand_ovl_dirs(mnt_table, mnt_table_size, arg) < 0)
+               goto destroy_and_put;
+
+       /* allocate and set mount entries */
+       struct mnts *n = NULL;
+       for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
+               char *mntentry = NULL;
+               mntentry = set_mnt_entry(n);
+               if (!mntentry)
+                       goto destroy_and_put;
+               bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
+               free(mntentry);
+               if (!bret)
+                       goto destroy_and_put;
+       }
+
+       if (!clone->save_config(clone, NULL))
+               goto destroy_and_put;
+
+       if (!my_args.quiet)
+               printf("Created %s as clone of %s\n", arg->newname, arg->name);
+
+       if (!arg->daemonize && arg->argc) {
+               clone->want_daemonize(clone, true);
+               arg->daemonize = 1;
+       } else if (!arg->daemonize) {
+               clone->want_daemonize(clone, false);
+       }
+
+       started = clone->start(clone, 0, NULL);
+       if (!started)
+               goto destroy_and_put;
+
+       if (arg->daemonize && arg->argc) {
+               ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv);
+               if (ret < 0)
+                       goto destroy_and_put;
+               clone->shutdown(clone, -1);
+       }
+
+       free_mnts();
+       lxc_container_put(clone);
+       return 0;
+
+destroy_and_put:
+       if (started)
+               clone->shutdown(clone, -1);
+       if (!started || clone->lxc_conf->ephemeral != 1)
+               clone->destroy(clone);
+       free_mnts();
+       lxc_container_put(clone);
+       return -1;
+}
+
+static int do_clone_rename(struct lxc_container *c, char *newname)
+{
+       if (!c->rename(c, newname)) {
+               ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);
+               return -1;
+       }
+
+       INFO("Renamed container %s to %s\n", c->name, newname);
+
+       return 0;
+}
+
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,
+                        char **args)
+{
+       int ret = 0;
+
+       switch (task) {
+       case DESTROY:
+               ret = do_clone_ephemeral(c, &my_args, args, flags);
+               break;
+       case RENAME:
+               ret = do_clone_rename(c, my_args.newname);
+               break;
+       default:
+               ret = do_clone(c, my_args.newname, my_args.newpath, flags,
+                              my_args.bdevtype, my_args.fssize, my_args.task,
+                              args);
+               break;
+       }
+
+       return ret;
+}
+
+static void free_mnts()
+{
+       unsigned int i;
+       struct mnts *n = NULL;
+
+       for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
+               free(n->src);
+               free(n->dest);
+               free(n->options);
+               free(n->upper);
+               free(n->workdir);
+       }
+       free(mnt_table);
+       mnt_table = NULL;
+       mnt_table_size = 0;
+}
+
+/* we pass fssize in bytes */
+static uint64_t get_fssize(char *s)
+{
+       uint64_t ret;
+       char *end;
+
+       ret = strtoull(s, &end, 0);
+       if (end == s) {
+               if (!my_args.quiet)
+                       fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
+               return 0;
+       }
+       while (isblank(*end))
+               end++;
+       if (*end == '\0') {
+               ret *= 1024ULL * 1024ULL; // MB by default
+       } else if (*end == 'b' || *end == 'B') {
+               ret *= 1ULL;
+       } else if (*end == 'k' || *end == 'K') {
+               ret *= 1024ULL;
+       } else if (*end == 'm' || *end == 'M') {
+               ret *= 1024ULL * 1024ULL;
+       } else if (*end == 'g' || *end == 'G') {
+               ret *= 1024ULL * 1024ULL * 1024ULL;
+       } else if (*end == 't' || *end == 'T') {
+               ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
+       } else {
+               if (!my_args.quiet)
+                       fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
+               return 0;
+       }
+
+       return ret;
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+       char *subopts = NULL;
+       char *mntparameters = NULL;
+       switch (c) {
+       case 'N':
+               args->newname = arg;
+               break;
+       case 'p':
+               args->newpath = arg;
+               break;
+       case 'R':
+               args->task = RENAME;
+               break;
+       case 's':
+               args->task = SNAP;
+               break;
+       case 'F':
+               args->daemonize = 0;
+               break;
+       case 'd':
+               args->daemonize = 1;
+               break;
+       case 'e':
+               args->task = DESTROY;
+               break;
+       case 'm':
+               subopts = optarg;
+               if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
+                       return -1;
+               break;
+       case 'B':
+               args->bdevtype = arg;
+               break;
+       case 'L':
+               args->fssize = get_fssize(optarg);
+               break;
+       case 'D':
+               args->keepdata = 1;
+               break;
+       case 'K':
+               args->keepname = 1;
+               break;
+       case 'M':
+               args->keepmac = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int parse_aufs_mnt(char *mntstring, enum mnttype type)
+{
+       int len = 0;
+       const char *xinopath = "/dev/shm/aufs.xino";
+       char **mntarray = NULL;
+       struct mnts *m = NULL;
+
+       m = add_mnt(&mnt_table, &mnt_table_size, type);
+       if (!m)
+               goto err;
+
+       mntarray = lxc_string_split(mntstring, ':');
+       if (!mntarray)
+               goto err;
+
+       m->src = construct_path(mntarray[0], true);
+       if (!m->src)
+               goto err;
+
+       len = lxc_array_len((void **)mntarray);
+       if (len == 1) /* aufs=src */
+               m->dest = construct_path(mntarray[0], false);
+       else if (len == 2) /* aufs=src:dest */
+               m->dest = construct_path(mntarray[1], false);
+       else
+               INFO("Excess elements in mount specification");
+
+       if (!m->dest)
+               goto err;
+
+       m->workdir = strdup(xinopath);
+       if (!m->workdir)
+               goto err;
+
+       lxc_free_array((void **)mntarray, free);
+       return 0;
+
+err:
+       free_mnts();
+       lxc_free_array((void **)mntarray, free);
+       return -1;
+}
+
+static int parse_bind_mnt(char *mntstring, enum mnttype type)
+{
+       int len = 0;
+       char **mntarray = NULL;
+       struct mnts *m = NULL;
+
+       m = add_mnt(&mnt_table, &mnt_table_size, type);
+       if (!m)
+               goto err;
+
+       mntarray = lxc_string_split(mntstring, ':');
+       if (!mntarray)
+               goto err;
+
+       m->src = construct_path(mntarray[0], true);
+       if (!m->src)
+               goto err;
+
+       len = lxc_array_len((void **)mntarray);
+       if (len == 1) { /* bind=src */
+               m->dest = construct_path(mntarray[0], false);
+       } else if (len == 2) { /* bind=src:option or bind=src:dest */
+               if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)
+                       m->options = strdup("rw");
+
+               if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)
+                       m->options = strdup("ro");
+
+               if (m->options)
+                       m->dest = construct_path(mntarray[0], false);
+               else
+                       m->dest = construct_path(mntarray[1], false);
+       } else if (len == 3) { /* bind=src:dest:option */
+                       m->dest = construct_path(mntarray[1], false);
+                       m->options = strdup(mntarray[2]);
+       } else {
+               INFO("Excess elements in mount specification");
+       }
+
+       if (!m->dest)
+               goto err;
+
+       if (!m->options)
+               m->options = strdup("rw");
+
+       if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
+                           strncmp(m->options, "ro", strlen(m->options))))
+               goto err;
+
+       lxc_free_array((void **)mntarray, free);
+       return 0;
+
+err:
+       free_mnts();
+       lxc_free_array((void **)mntarray, free);
+       return -1;
+}
+
+static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameters)
+{
+       while (*subopts != '\0') {
+               switch (getsubopt(&subopts, keys, &mntparameters)) {
+               case LXC_MNT_BIND:
+                       if (parse_bind_mnt(mntparameters, LXC_MNT_BIND) < 0)
+                               return -1;
+                       break;
+               case LXC_MNT_OVL:
+                       if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
+                               return -1;
+                       break;
+               case LXC_MNT_AUFS:
+                       if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
+                               return -1;
+                       break;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int parse_ovl_mnt(char *mntstring, enum mnttype type)
+{
+       int len = 0;
+       char **mntarray = NULL;
+       struct mnts *m;
+
+       m = add_mnt(&mnt_table, &mnt_table_size, type);
+       if (!m)
+               goto err;
+
+       mntarray = lxc_string_split(mntstring, ':');
+       if (!mntarray)
+               goto err;
+
+       m->src = construct_path(mntarray[0], true);
+       if (!m->src)
+               goto err;
+
+       len = lxc_array_len((void **)mntarray);
+       if (len == 1) /* overlay=src */
+               m->dest = construct_path(mntarray[0], false);
+       else if (len == 2) /* overlay=src:dest */
+               m->dest = construct_path(mntarray[1], false);
+       else
+               INFO("Excess elements in mount specification");
+
+       if (!m->dest)
+               goto err;
+
+       lxc_free_array((void **)mntarray, free);
+       return 0;
+
+err:
+       free_mnts();
+       lxc_free_array((void **)mntarray, free);
+       return -1;
+}
index f1094fb..0634397 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <lxc/lxccontainer.h>
-
-#include <stdio.h>
-#include <libgen.h>
-#include <unistd.h>
 #include <ctype.h>
 #include <fcntl.h>
-#include <sys/types.h>
+#include <libgen.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <lxc/lxccontainer.h>
+#include <sys/types.h>
 
-#include "lxc.h"
-#include "log.h"
-#include "bdev.h"
 #include "arguments.h"
+#include "log.h"
+#include "lxc.h"
 #include "utils.h"
+#include "bdev/bdev.h"
 
 lxc_log_define(lxc_create_ui, lxc);
 
@@ -81,6 +80,8 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
        case '4': args->fssize = get_fssize(arg); break;
        case '5': args->zfsroot = arg; break;
        case '6': args->dir = arg; break;
+       case '7': args->rbdname = arg; break;
+       case '8': args->rbdpool = arg; break;
        }
        return 0;
 }
@@ -96,10 +97,13 @@ static const struct option my_longopts[] = {
        {"fssize", required_argument, 0, '4'},
        {"zfsroot", required_argument, 0, '5'},
        {"dir", required_argument, 0, '6'},
+       {"rbdname", required_argument, 0, '7'},
+       {"rbdpool", required_argument, 0, '8'},
        LXC_COMMON_OPTIONS
 };
 
-static void create_helpfn(const struct lxc_arguments *args) {
+static void create_helpfn(const struct lxc_arguments *args)
+{
        char *argv[3], *path;
        pid_t pid;
 
@@ -117,38 +121,51 @@ static void create_helpfn(const struct lxc_arguments *args) {
        argv[0] = path;
        argv[1] = "-h";
        argv[2] = NULL;
+
        execv(path, argv);
        ERROR("Error executing %s -h", path);
-       exit(1);
+       exit(EXIT_FAILURE);
 }
 
 static struct lxc_arguments my_args = {
        .progname = "lxc-create",
        .helpfn   = create_helpfn,
        .help     = "\
---name=NAME -t template [-w] [-r] [-P lxcpath]\n\
+--name=NAME --template=TEMPLATE [OPTION...]\n\
 \n\
 lxc-create creates a container\n\
 \n\
 Options :\n\
-  -n, --name=NAME    NAME of the container\n\
-  -f, --config=file  Initial configuration file\n\
-  -t, --template=t   Template to use to setup container\n\
-  -B, --bdev=BDEV    Backing store type to use\n\
-  -P, --lxcpath=PATH Place container under PATH\n\
-  --lvname=LVNAME    Use LVM lv name LVNAME\n\
-                     (Default: container name)\n\
-  --vgname=VG        Use LVM vg called VG\n\
-                     (Default: lxc)\n\
-  --thinpool=TP      Use LVM thin pool called TP\n\
-                     (Default: lxc)\n\
-  --fstype=TYPE      Create fstype TYPE\n\
-                     (Default: ext3)\n\
-  --fssize=SIZE[U]   Create filesystem of size SIZE * unit U (bBkKmMgGtT)\n\
-                     (Default: 1G, default unit: M)\n\
-  --dir=DIR          Place rootfs directory under DIR\n\
-  --zfsroot=PATH     Create zfs under given zfsroot\n\
-                     (Default: tank/lxc)\n",
+  -n, --name=NAME               NAME of the container\n\
+  -f, --config=CONFIG           Initial configuration file\n\
+  -t, --template=TEMPLATE       Template to use to setup container\n\
+  -B, --bdev=BDEV               Backing store type to use\n\
+      --dir=DIR                 Place rootfs directory under DIR\n\
+\n\
+  BDEV options for LVM (with -B/--bdev lvm):\n\
+      --lvname=LVNAME           Use LVM lv name LVNAME\n\
+                                (Default: container name)\n\
+      --vgname=VG               Use LVM vg called VG\n\
+                                (Default: lxc)\n\
+      --thinpool=TP             Use LVM thin pool called TP\n\
+                                (Default: lxc)\n\
+\n\
+  BDEV options for Ceph RBD (with -B/--bdev rbd) :\n\
+      --rbdname=RBDNAME         Use Ceph RBD name RBDNAME\n\
+                                (Default: container name)\n\
+      --rbdpool=POOL            Use Ceph RBD pool name POOL\n\
+                                (Default: lxc)\n\
+\n\
+  BDEV option for ZFS (with -B/--bdev zfs) :\n\
+      --zfsroot=PATH            Create zfs under given zfsroot\n\
+                                (Default: tank/lxc)\n\
+\n\
+  BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :\n\
+      --fstype=TYPE             Create fstype TYPE\n\
+                                (Default: ext3)\n\
+      --fssize=SIZE[U]          Create filesystem of\n\
+                                size SIZE * unit U (bBkKmMgGtT)\n\
+                                (Default: 1G, default unit: M)\n",
        .options  = my_longopts,
        .parser   = my_parser,
        .checker  = NULL,
@@ -159,7 +176,8 @@ static bool validate_bdev_args(struct lxc_arguments *a)
        if (strcmp(a->bdevtype, "best") != 0) {
                if (a->fstype || a->fssize) {
                        if (strcmp(a->bdevtype, "lvm") != 0 &&
-                           strcmp(a->bdevtype, "loop") != 0) {
+                           strcmp(a->bdevtype, "loop") != 0 &&
+                           strcmp(a->bdevtype, "rbd") != 0) {
                                fprintf(stderr, "filesystem type and size are only valid with block devices\n");
                                return false;
                        }
@@ -170,6 +188,12 @@ static bool validate_bdev_args(struct lxc_arguments *a)
                                return false;
                        }
                }
+               if (strcmp(a->bdevtype, "rbd") != 0) {
+                       if (a->rbdname || a->rbdpool) {
+                               fprintf(stderr, "--rbdname and --rbdpool are only valid with -B rbd\n");
+                               return false;
+                       }
+               }
                if (strcmp(a->bdevtype, "zfs") != 0) {
                        if (a->zfsroot) {
                                fprintf(stderr, "zfsroot is only valid with -B zfs\n");
@@ -187,20 +211,20 @@ int main(int argc, char *argv[])
        int flags = 0;
 
        if (lxc_arguments_parse(&my_args, argc, argv))
-               exit(1);
+               exit(EXIT_FAILURE);
 
        if (!my_args.log_file)
                my_args.log_file = "none";
 
        if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
                         my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-               exit(1);
+               exit(EXIT_FAILURE);
        lxc_log_options_no_override();
 
        if (!my_args.template) {
                fprintf(stderr, "A template must be specified.\n");
                fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n");
-               exit(1);
+               exit(EXIT_FAILURE);
        }
 
        if (strcmp(my_args.template, "none") == 0)
@@ -209,36 +233,44 @@ int main(int argc, char *argv[])
        memset(&spec, 0, sizeof(spec));
        if (!my_args.bdevtype)
                my_args.bdevtype = "_unset";
+
        if (!validate_bdev_args(&my_args))
-               exit(1);
+               exit(EXIT_FAILURE);
 
        if (strcmp(my_args.bdevtype, "none") == 0)
                my_args.bdevtype = "dir";
 
+       // Final check whether the user gave use a valid bdev type.
+       if (!is_valid_bdev_type(my_args.bdevtype) && strcmp(my_args.bdevtype, "_unset")) {
+               fprintf(stderr, "%s is not a valid backing storage type.\n", my_args.bdevtype);
+               exit(EXIT_FAILURE);
+       }
+
        if (geteuid()) {
                if (mkdir_p(my_args.lxcpath[0], 0755)) {
-                       exit(1);
+                       exit(EXIT_FAILURE);
                }
                if (access(my_args.lxcpath[0], O_RDWR) < 0) {
                        fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
-                       exit(1);
+                       exit(EXIT_FAILURE);
                }
                if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
                                strcmp(my_args.bdevtype, "btrfs")) {
                        fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
-                       exit(1);
+                       exit(EXIT_FAILURE);
                }
        }
 
 
        c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
        if (!c) {
-               fprintf(stderr, "System error loading container\n");
-               exit(1);
+               fprintf(stderr, "Failed to create lxc container.\n");
+               exit(EXIT_FAILURE);
        }
        if (c->is_defined(c)) {
+               lxc_container_put(c);
                fprintf(stderr, "Container already exists\n");
-               exit(1);
+               exit(EXIT_FAILURE);
        }
        if (my_args.configfile)
                c->load_config(c, my_args.configfile);
@@ -250,11 +282,12 @@ int main(int argc, char *argv[])
        if (my_args.fssize)
                spec.fssize = my_args.fssize;
 
-       if (strcmp(my_args.bdevtype, "zfs") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
+       if ((strcmp(my_args.bdevtype, "zfs") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
                if (my_args.zfsroot)
                        spec.zfs.zfsroot = my_args.zfsroot;
        }
-       if (strcmp(my_args.bdevtype, "lvm") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
+
+       if ((strcmp(my_args.bdevtype, "lvm") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
                if (my_args.lvname)
                        spec.lvm.lv = my_args.lvname;
                if (my_args.vgname)
@@ -262,19 +295,30 @@ int main(int argc, char *argv[])
                if (my_args.thinpool)
                        spec.lvm.thinpool = my_args.thinpool;
        }
-       if (my_args.dir) {
-               spec.dir = my_args.dir;
+
+       if ((strcmp(my_args.bdevtype, "rbd") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
+               if (my_args.rbdname)
+                       spec.rbd.rbdname = my_args.rbdname;
+               if (my_args.rbdpool)
+                       spec.rbd.rbdpool = my_args.rbdpool;
        }
 
+       if (my_args.dir)
+               spec.dir = my_args.dir;
+
        if (strcmp(my_args.bdevtype, "_unset") == 0)
                my_args.bdevtype = NULL;
+
        if (my_args.quiet)
                flags = LXC_CREATE_QUIET;
+
        if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
                ERROR("Error creating container %s", c->name);
                lxc_container_put(c);
-               exit(1);
+               exit(EXIT_FAILURE);
        }
+
+       lxc_container_put(c);
        INFO("container %s created", c->name);
-       exit(0);
+       exit(EXIT_SUCCESS);
 }
index 955fc23..c6e3454 100644 (file)
@@ -17,6 +17,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _GNU_SOURCE
 #include <lxc/lxccontainer.h>
 
 #include <stdio.h>
 
 lxc_log_define(lxc_destroy_ui, lxc);
 
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-       switch (c) {
-       case 'f': args->force = 1; break;
-       }
-       return 0;
-}
+static int my_parser(struct lxc_arguments* args, int c, char* arg);
+static bool quiet;
 
 static const struct option my_longopts[] = {
        {"force", no_argument, 0, 'f'},
+       {"snapshots", no_argument, 0, 's'},
        LXC_COMMON_OPTIONS
 };
 
@@ -52,61 +49,211 @@ static struct lxc_arguments my_args = {
 lxc-destroy destroys a container with the identifier NAME\n\
 \n\
 Options :\n\
-  -n, --name=NAME   NAME for name of the container\n\
+  -n, --name=NAME   NAME of the container\n\
+  -s, --snapshots   destroy including all snapshots\n\
   -f, --force       wait for the container to shut down\n",
        .options  = my_longopts,
        .parser   = my_parser,
        .checker  = NULL,
+       .task     = DESTROY,
 };
 
+static bool do_destroy(struct lxc_container *c);
+static bool do_destroy_with_snapshots(struct lxc_container *c);
+
 int main(int argc, char *argv[])
 {
        struct lxc_container *c;
+       bool bret;
 
        if (lxc_arguments_parse(&my_args, argc, argv))
-               exit(1);
+               exit(EXIT_FAILURE);
 
        if (!my_args.log_file)
                my_args.log_file = "none";
 
        if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
                         my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-               exit(1);
+               exit(EXIT_FAILURE);
        lxc_log_options_no_override();
+       if (my_args.quiet)
+               quiet = true;
 
        c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
        if (!c) {
-               fprintf(stderr, "System error loading container\n");
-               exit(1);
+               if (!quiet)
+                       fprintf(stderr, "System error loading container\n");
+               exit(EXIT_FAILURE);
        }
 
        if (!c->may_control(c)) {
-               fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
+               if (!quiet)
+                       fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
                lxc_container_put(c);
-               exit(1);
+               exit(EXIT_FAILURE);
        }
 
        if (!c->is_defined(c)) {
-               fprintf(stderr, "Container is not defined\n");
+               if (!quiet)
+                       fprintf(stderr, "Container is not defined\n");
                lxc_container_put(c);
-               exit(1);
+               exit(EXIT_FAILURE);
+       }
+
+       if (my_args.task == SNAP) {
+               bret = do_destroy_with_snapshots(c);
+               if (bret && !quiet)
+                       printf("Destroyed container %s including snapshots \n", my_args.name);
+       } else {
+               bret = do_destroy(c);
+               if (bret && !quiet)
+                       printf("Destroyed container %s\n", my_args.name);
+       }
+
+       lxc_container_put(c);
+
+       if (bret)
+               exit(EXIT_SUCCESS);
+       exit(EXIT_FAILURE);
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+       switch (c) {
+       case 'f': args->force = 1; break;
+       case 's': args->task = SNAP; break;
+       }
+       return 0;
+}
+
+static bool do_destroy(struct lxc_container *c)
+{
+       bool bret = true;
+       char path[MAXPATHLEN];
+
+       /* First check whether the container has dependent clones or snapshots. */
+       int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               return false;
+
+       if (file_exists(path)) {
+               if (!quiet)
+                       fprintf(stdout, "Destroying %s failed: %s has clones.\n", c->name, c->name);
+               return false;
+       }
+
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               return false;
+
+       if (dir_exists(path)) {
+               if (!quiet)
+                       fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
+               return false;
        }
 
        if (c->is_running(c)) {
-               if (!my_args.force) {
+               if (!my_args.force && !quiet) {
                        fprintf(stderr, "%s is running\n", my_args.name);
-                       lxc_container_put(c);
-                       exit(1);
+                       return false;
                }
+               /* If the container was ephemeral it will be removed on shutdown. */
                c->stop(c);
        }
 
-       if (!c->destroy(c)) {
-               fprintf(stderr, "Destroying %s failed\n", my_args.name);
-               lxc_container_put(c);
-               exit(1);
+       /* If the container was ephemeral we have already removed it when we
+        * stopped it. */
+       if (c->is_defined(c) && !c->lxc_conf->ephemeral)
+               bret = c->destroy(c);
+
+       if (!bret) {
+               if (!quiet)
+                       fprintf(stderr, "Destroying %s failed\n", my_args.name);
+               return false;
        }
 
-       lxc_container_put(c);
-       exit(0);
+       return true;
+}
+
+static bool do_destroy_with_snapshots(struct lxc_container *c)
+{
+       struct lxc_container *c1;
+       struct stat fbuf;
+       bool bret = false;
+       char path[MAXPATHLEN];
+       char *buf = NULL;
+       char *lxcpath = NULL;
+       char *lxcname = NULL;
+       char *scratch = NULL;
+       int fd;
+       int ret;
+       int counter = 0;
+
+       /* Destroy clones. */
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               return false;
+
+       fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (fd >= 0) {
+               ret = fstat(fd, &fbuf);
+               if (ret < 0) {
+                       close(fd);
+                       return false;
+               }
+
+               /* Make sure that the string is \0 terminated. */
+               buf = calloc(fbuf.st_size + 1, sizeof(char));
+               if (!buf) {
+                       SYSERROR("failed to allocate memory");
+                       close(fd);
+                       return false;
+               }
+
+               ret = read(fd, buf, fbuf.st_size);
+               if (ret < 0) {
+                       ERROR("could not read %s", path);
+                       close(fd);
+                       free(buf);
+                       return false;
+               }
+               close(fd);
+
+               while ((lxcpath = strtok_r(!counter ? buf : NULL, "\n", &scratch))) {
+                       if (!(lxcname = strtok_r(NULL, "\n", &scratch)))
+                               break;
+                       c1 = lxc_container_new(lxcname, lxcpath);
+                       if (!c1) {
+                               counter++;
+                               continue;
+                       }
+                       /* We do not destroy recursively. If a clone of a clone
+                        * has clones or snapshots the user should remove it
+                        * explicitly. */
+                       if (!do_destroy(c1)) {
+                               lxc_container_put(c1);
+                               free(buf);
+                               return false;
+                       }
+                       lxc_container_put(c1);
+                       counter++;
+               }
+               free(buf);
+       }
+
+       /* Destroy snapshots located in the containers snap/ folder. */
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+       if (ret < 0 || ret >= MAXPATHLEN)
+               return false;
+
+       if (dir_exists(path))
+               bret = c->destroy_with_snapshots(c);
+       else
+               bret = do_destroy(c);
+
+       if (bret && !quiet)
+               printf("Destroyed container %s including snapshots \n", my_args.name);
+
+       return bret;
 }
+
index d2c1248..50d481f 100644 (file)
@@ -59,7 +59,9 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
        switch (c) {
        case 'f': args->rcfile = arg; break;
-       case 's': return lxc_config_define_add(&defines, arg);
+       case 's': return lxc_config_define_add(&defines, arg); break;
+       case 'u': args->uid = atoi(arg); break;
+       case 'g': args->gid = atoi(arg);
        }
        return 0;
 }
@@ -67,6 +69,8 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 static const struct option my_longopts[] = {
        {"rcfile", required_argument, 0, 'f'},
        {"define", required_argument, 0, 's'},
+       {"uid", required_argument, 0, 'u'},
+       {"gid", required_argument, 0, 'g'},
        LXC_COMMON_OPTIONS
 };
 
@@ -81,7 +85,9 @@ and execs COMMAND into this container.\n\
 Options :\n\
   -n, --name=NAME      NAME of the container\n\
   -f, --rcfile=FILE    Load configuration file FILE\n\
-  -s, --define KEY=VAL Assign VAL to configuration variable KEY\n",
+  -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
+  -u, --uid=UID Execute COMMAND with UID inside the container\n\
+  -g, --gid=GID Execute COMMAND with GID inside the container\n",
        .options  = my_longopts,
        .parser   = my_parser,
        .checker  = my_checker,
@@ -139,6 +145,12 @@ int main(int argc, char *argv[])
        if (lxc_config_define_load(&defines, conf))
                return 1;
 
+       if (my_args.uid)
+               conf->init_uid = my_args.uid;
+
+       if (my_args.gid)
+               conf->init_gid = my_args.gid;
+
        ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0], false);
 
        lxc_conf_free(conf);
diff --git a/src/lxc/lxc_ls.c b/src/lxc/lxc_ls.c
new file mode 100644 (file)
index 0000000..1a9969a
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ *
+ * Copyright © 2016 Christian Brauner <christian.brauner@mailbox.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <termios.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "arguments.h"
+#include "conf.h"
+#include "config.h"
+#include "confile.h"
+#include "log.h"
+#include "lxc.h"
+#include "utils.h"
+
+lxc_log_define(lxc_ls, lxc);
+
+#define LINELEN 1024
+/* Per default we only allow five levels of recursion to protect the stack at
+ * least a little bit. */
+#define MAX_NESTLVL 5
+
+#define LS_FROZEN 1
+#define LS_STOPPED 2
+#define LS_ACTIVE 3
+#define LS_RUNNING 4
+#define LS_NESTING 5
+#define LS_FILTER 6
+
+#ifndef SOCK_CLOEXEC
+#  define SOCK_CLOEXEC                02000000
+#endif
+
+/* Store container info. */
+struct ls {
+       char *name;
+       char *state;
+       char *groups;
+       char *interface;
+       char *ipv4;
+       char *ipv6;
+       unsigned int nestlvl;
+       pid_t init;
+       double ram;
+       double swap;
+       bool autostart;
+       bool running;
+};
+
+/* Keep track of field widths for printing. */
+struct lengths {
+       unsigned int name_length;
+       unsigned int state_length;
+       unsigned int groups_length;
+       unsigned int interface_length;
+       unsigned int ipv4_length;
+       unsigned int ipv6_length;
+       unsigned int init_length;
+       unsigned int ram_length;
+       unsigned int swap_length;
+       unsigned int autostart_length;
+};
+
+static int ls_deserialize(int rpipefd, struct ls **m, size_t *len);
+static void ls_field_width(const struct ls *l, const size_t size,
+               struct lengths *lht);
+static void ls_free(struct ls *l, size_t size);
+static void ls_free_arr(char **arr, size_t size);
+static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
+               const char *basepath, const char *parent, unsigned int lvl,
+               char **lockpath, size_t len_lockpath, char **grps_must,
+               size_t grps_must_len);
+static char *ls_get_cgroup_item(struct lxc_container *c, const char *item);
+static char *ls_get_config_item(struct lxc_container *c, const char *item,
+               bool running);
+static char *ls_get_groups(struct lxc_container *c, bool running);
+static char *ls_get_ips(struct lxc_container *c, const char *inet);
+struct wrapargs {
+       const struct lxc_arguments *args;
+       char **grps_must;
+       size_t grps_must_len;
+       int pipefd[2];
+       size_t *size;
+       const char *parent;
+       unsigned int nestlvl;
+};
+/*
+ * Takes struct wrapargs as argument.
+ */
+static int ls_get_wrapper(void *wrap);
+/*
+ * To calculate swap usage we should not simply check memory.usage_in_bytes and
+ * memory.memsw.usage_in_bytes and then do:
+ *     swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
+ * because we might receive an incorrect/negative value.
+ * Instead we check memory.stat and check the "swap" value.
+ */
+static double ls_get_swap(struct lxc_container *c);
+static unsigned int ls_get_term_width(void);
+static char *ls_get_interface(struct lxc_container *c);
+static bool ls_has_all_grps(const char *has, char **must, size_t must_len);
+static struct ls *ls_new(struct ls **ls, size_t *size);
+/*
+ * Print user-specified fancy format.
+ */
+static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
+               size_t size, const char *fancy_fmt);
+/*
+ * Only print names of containers.
+ */
+static void ls_print_names(struct ls *l, struct lengths *lht,
+               size_t ls_arr, size_t termwidth);
+/*
+ * Print default fancy format.
+ */
+static void ls_print_table(struct ls *l, struct lengths *lht,
+               size_t size);
+/*
+ * id can only be 79 + \0 chars long.
+ */
+static int ls_read_and_grow_buf(const int rpipefd, char **save_buf,
+               const char *id, ssize_t nbytes_id,
+               char **read_buf, ssize_t *read_buf_len);
+static int ls_remove_lock(const char *path, const char *name,
+               char **lockpath, size_t *len_lockpath, bool recalc);
+static int ls_serialize(int wpipefd, struct ls *n);
+static int ls_write(const int wpipefd, const char *id, ssize_t nbytes_id,
+               const char *s);
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
+
+static const struct option my_longopts[] = {
+       {"line", no_argument, 0, '1'},
+       {"fancy", no_argument, 0, 'f'},
+       {"fancy-format", required_argument, 0, 'F'},
+       {"active", no_argument, 0, LS_ACTIVE},
+       {"running", no_argument, 0, LS_RUNNING},
+       {"frozen", no_argument, 0, LS_FROZEN},
+       {"stopped", no_argument, 0, LS_STOPPED},
+       {"nesting", optional_argument, 0, LS_NESTING},
+       {"groups", required_argument, 0, 'g'},
+       {"filter", required_argument, 0, LS_FILTER},
+       LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+       .progname = "lxc-ls",
+       .help = "\n\
+[-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+[-1] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+[-f] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+\n\
+lxc-ls list containers\n\
+\n\
+Options :\n\
+  -1, --line        show one entry per line\n\
+  -f, --fancy       column-based output\n\
+  -F, --fancy-format column-based output\n\
+  --active           list only active containers\n\
+  --running          list only running containers\n\
+  --frozen           list only frozen containers\n\
+  --stopped          list only stopped containers\n\
+  --nesting=NUM      list nested containers up to NUM (default is 5) levels of nesting\n\
+  --filter=REGEX     filter container names by regular expression\n\
+  -g --groups        comma separated list of groups a container must have to be displayed\n",
+       .options = my_longopts,
+       .parser = my_parser,
+       .ls_nesting = 0,
+};
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_FAILURE;
+       /*
+        * The lxc parser requires that my_args.name is set. So let's satisfy
+        * that condition by setting a dummy name which is never used.
+        */
+       my_args.name  = "";
+       if (lxc_arguments_parse(&my_args, argc, argv))
+               exit(EXIT_FAILURE);
+
+       if (!my_args.log_file)
+               my_args.log_file = "none";
+
+       /*
+        * We set the first argument that usually takes my_args.name to NULL so
+        * that the log is only used when the user specifies a file.
+        */
+       if (lxc_log_init(NULL, my_args.log_file, my_args.log_priority,
+                        my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+               exit(EXIT_FAILURE);
+       lxc_log_options_no_override();
+
+       struct lengths max_len = {
+               /* default header length */
+               .name_length = 4,      /* NAME */
+               .state_length = 5,     /* STATE */
+               .groups_length = 6,    /* GROUPS */
+               .interface_length = 9, /* INTERFACE */
+               .ipv4_length = 4,      /* IPV4 */
+               .ipv6_length = 4,      /* IPV6 */
+               .init_length = 3,      /* PID */
+               .ram_length = 3,       /* RAM */
+               .swap_length = 4,      /* SWAP */
+               .autostart_length = 9, /* AUTOSTART */
+       };
+
+       char **grps = NULL;
+       size_t ngrps = 0;
+       if (my_args.groups) {
+               grps = lxc_string_split_and_trim(my_args.groups, ',');
+               ngrps = lxc_array_len((void **)grps);
+       }
+
+       struct ls *ls_arr = NULL;
+       size_t ls_size = 0;
+       /* &(char *){NULL} is no magic. It's just a compound literal which
+        * avoids having a pointless variable in main() that serves no purpose
+        * here. */
+       int status = ls_get(&ls_arr, &ls_size, &my_args, "", NULL, 0, &(char *){NULL}, 0, grps, ngrps);
+       if (!ls_arr && status == 0)
+               /* We did not fail. There was just nothing to do. */
+               exit(EXIT_SUCCESS);
+       else if (!ls_arr || status == -1)
+               goto out;
+
+       ls_field_width(ls_arr, ls_size, &max_len);
+       if (my_args.ls_fancy && !my_args.ls_fancy_format) {
+               ls_print_table(ls_arr, &max_len, ls_size);
+       } else if (my_args.ls_fancy && my_args.ls_fancy_format) {
+               ls_print_fancy_format(ls_arr, &max_len, ls_size, my_args.ls_fancy_format);
+       } else {
+               unsigned int cols = 0;
+               if (!my_args.ls_line)
+                       cols = ls_get_term_width();
+               ls_print_names(ls_arr, &max_len, ls_size, cols);
+       }
+
+       ret = EXIT_SUCCESS;
+
+out:
+       ls_free(ls_arr, ls_size);
+       lxc_free_array((void **)grps, free);
+
+       exit(ret);
+}
+
+static void ls_free(struct ls *l, size_t size)
+{
+       size_t i;
+       struct ls *m = NULL;
+       for (i = 0, m = l; i < size; i++, m++) {
+               free(m->groups);
+               free(m->interface);
+               free(m->ipv4);
+               free(m->ipv6);
+               free(m->name);
+               free(m->state);
+       }
+       free(l);
+}
+
+static char *ls_get_config_item(struct lxc_container *c, const char *item,
+               bool running)
+{
+       if (running)
+               return c->get_running_config_item(c, item);
+
+       size_t len = c->get_config_item(c, item, NULL, 0);
+       if (len <= 0)
+               return NULL;
+
+       char *val = malloc((len + 1) * sizeof(*val));
+       if (!val)
+               return NULL;
+
+       if ((size_t)c->get_config_item(c, item, val, len + 1) != len) {
+               free(val);
+               val = NULL;
+       }
+
+       return val;
+}
+
+static void ls_free_arr(char **arr, size_t size)
+{
+       size_t i;
+       for (i = 0; i < size; i++) {
+               free(arr[i]);
+       }
+       free(arr);
+}
+
+static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
+               const char *basepath, const char *parent, unsigned int lvl,
+               char **lockpath, size_t len_lockpath, char **grps_must,
+               size_t grps_must_len)
+{
+       /* As ls_get() is non-tail recursive we face the inherent danger of
+        * blowing up the stack at some level of nesting. To have at least some
+        * security we define MAX_NESTLVL to be 5. That should be sufficient for
+        * most users. The argument lvl can be used to keep track of the level
+        * of nesting we are at. If lvl is greater than the allowed default
+        * level or the level the user specified on the command line we return
+        * and unwind the stack. */
+       if (lvl > args->ls_nesting)
+               return 0;
+
+       int num = 0, ret = -1;
+       char **containers = NULL;
+       /* If we, at some level of nesting, encounter a stopped container but
+        * want to retrieve nested containers we need to build an absolute path
+        * beginning from it. Initially, at nesting level 0, basepath will
+        * simply be the empty string and path will simply be whatever the
+        * default lxcpath or the path the user gave us is.  Basepath will also
+        * be the empty string in case we encounter a running container since we
+        * can simply attach to its namespace to retrieve nested containers. */
+       char *path = lxc_append_paths(basepath, args->lxcpath[0]);
+       if (!path)
+               goto out;
+
+       if (!dir_exists(path)) {
+               ret = 0;
+               goto out;
+       }
+
+       /* Do not do more work than is necessary right from the start. */
+       if (args->ls_active || (args->ls_active && args->ls_frozen))
+               num = list_active_containers(path, &containers, NULL);
+       else
+               num = list_all_containers(path, &containers, NULL);
+       if (num == -1) {
+               num = 0;
+               goto out;
+       }
+
+       char *tmp = NULL;
+       int check;
+       struct ls *l = NULL;
+       struct lxc_container *c = NULL;
+       size_t i;
+       for (i = 0; i < (size_t)num; i++) {
+               char *name = containers[i];
+
+               /* Filter container names by regex the user gave us. */
+               if (args->ls_filter || args->argc == 1) {
+                       regex_t preg;
+                       tmp = args->ls_filter ? args->ls_filter : args->argv[0];
+                       check = regcomp(&preg, tmp, REG_NOSUB | REG_EXTENDED);
+                       if (check == REG_ESPACE) /* we're out of memory */
+                               goto out;
+                       else if (check != 0)
+                               continue;
+                       check = regexec(&preg, name, 0, NULL, 0);
+                       regfree(&preg);
+                       if (check != 0)
+                               continue;
+               }
+
+               errno = 0;
+               c = lxc_container_new(name, path);
+               if ((errno == ENOMEM) && !c)
+                       goto out;
+               else if (!c)
+                       continue;
+
+               if (!c->is_defined(c))
+                       goto put_and_next;
+
+               /* This does not allocate memory so no worries about freeing it
+                * when we goto next or out. */
+               const char *state_tmp = c->state(c);
+               if (!state_tmp)
+                       state_tmp = "UNKNOWN";
+
+               if (args->ls_running && !c->is_running(c))
+                       goto put_and_next;
+
+               if (args->ls_frozen && !args->ls_active && strcmp(state_tmp, "FROZEN"))
+                       goto put_and_next;
+
+               if (args->ls_stopped && strcmp(state_tmp, "STOPPED"))
+                       goto put_and_next;
+
+               bool running = c->is_running(c);
+
+               char *grp_tmp = ls_get_groups(c, running);
+               if (!ls_has_all_grps(grp_tmp, grps_must, grps_must_len)) {
+                       free(grp_tmp);
+                       goto put_and_next;
+               }
+
+               /* Now it makes sense to allocate memory. */
+               l = ls_new(m, size);
+               if (!l) {
+                       free(grp_tmp);
+                       goto put_and_next;
+               }
+
+               /* How deeply nested are we? */
+               l->nestlvl = lvl;
+
+               l->groups = grp_tmp;
+
+               l->running = running;
+
+               if (parent && args->ls_nesting && (args->ls_line || !args->ls_fancy))
+                       /* Prepend the name of the container with all its parents when
+                        * the user requests it. */
+                       l->name = lxc_append_paths(parent, name);
+               else
+                       /* Otherwise simply record the name. */
+                       l->name = strdup(name);
+               if (!l->name)
+                       goto put_and_next;
+
+               /* Do not record stuff the user did not explictly request. */
+               if (args->ls_fancy) {
+                       /* Maybe we should even consider the name sensitive and
+                        * hide it when you're not allowed to control the
+                        * container. */
+                       if (!c->may_control(c))
+                               goto put_and_next;
+
+                       l->state = strdup(state_tmp);
+                       if (!l->state)
+                               goto put_and_next;
+
+                       tmp = ls_get_config_item(c, "lxc.start.auto", running);
+                       if (tmp)
+                               l->autostart = atoi(tmp);
+                       free(tmp);
+
+                       if (running) {
+                               l->init = c->init_pid(c);
+
+                               l->interface = ls_get_interface(c);
+
+                               l->ipv4 = ls_get_ips(c, "inet");
+
+                               l->ipv6 = ls_get_ips(c, "inet6");
+
+                               tmp = ls_get_cgroup_item(c, "memory.usage_in_bytes");
+                               if (tmp) {
+                                       l->ram = strtoull(tmp, NULL, 0);
+                                       l->ram = l->ram / 1024 /1024;
+                                       free(tmp);
+                               }
+
+                               l->swap = ls_get_swap(c);
+                       }
+               }
+
+               /* Get nested containers: Only do this after we have gathered
+                * all other information we need. */
+               if (args->ls_nesting && running) {
+                       struct wrapargs wargs = (struct wrapargs){.args = NULL};
+                       /* Open a socket so that the child can communicate with us. */
+                       check = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, wargs.pipefd);
+                       if (check == -1)
+                               goto put_and_next;
+
+                       /* Set the next nesting level. */
+                       wargs.nestlvl = lvl + 1;
+                       /* Send in the parent for the next nesting level. */
+                       wargs.parent = l->name;
+                       wargs.args = args;
+                       wargs.grps_must = grps_must;
+                       wargs.grps_must_len = grps_must_len;
+
+                       pid_t out;
+
+                       lxc_attach_options_t aopt = LXC_ATTACH_OPTIONS_DEFAULT;
+                       aopt.env_policy = LXC_ATTACH_CLEAR_ENV;
+
+                       /* fork(): Attach to the namespace of the container and
+                        * run ls_get() in it which is called in ls_get_wrapper(). */
+                       check = c->attach(c, ls_get_wrapper, &wargs, &aopt, &out);
+                       /* close the socket */
+                       close(wargs.pipefd[1]);
+
+                       /* Retrieve all information we want from the child. */
+                       if (check == 0)
+                               if (ls_deserialize(wargs.pipefd[0], m, size) == -1)
+                                       goto put_and_next;
+
+                       /* Wait for the child to finish. */
+                       wait_for_pid(out);
+
+                       /* We've done all the communication we need so shutdown
+                        * the socket and close it. */
+                       shutdown(wargs.pipefd[0], SHUT_RDWR);
+                       close(wargs.pipefd[0]);
+               } else if (args->ls_nesting && !running) {
+                       /* This way of extracting the rootfs is not safe since
+                        * it will return very different things depending on the
+                        * storage backend that is used for the container. We
+                        * need a path-extractor function. We face the same
+                        * problem with the ovl_mkdir() function in
+                        * lxcoverlay.{c,h}. */
+                       char *curr_path = ls_get_config_item(c, "lxc.rootfs", running);
+                       if (!curr_path)
+                               goto put_and_next;
+
+                       /* Since the container is not running and we cannot
+                        * attach to it we need another strategy to retrieve
+                        * nested containers. What we do is simply create a
+                        * growing path which will lead us into the rootfs of
+                        * the next container where it stores its containers. */
+                       char *newpath = lxc_append_paths(basepath, curr_path);
+                       free(curr_path);
+                       if (!newpath)
+                               goto put_and_next;
+
+                       /* We want to remove all locks we create under
+                        * /run/lxc/lock so we create a string pointing us to
+                        * the lock path for the current container. */
+                       if (ls_remove_lock(path, name, lockpath, &len_lockpath, true) == -1)
+                               goto put_and_next;
+
+                       ls_get(m, size, args, newpath, l->name, lvl + 1, lockpath, len_lockpath, grps_must, grps_must_len);
+                       free(newpath);
+
+                       /* Remove the lock. No need to check for failure here. */
+                       ls_remove_lock(path, name, lockpath, &len_lockpath, false);
+               }
+
+put_and_next:
+               lxc_container_put(c);
+       }
+       ret = 0;
+
+out:
+       ls_free_arr(containers, num);
+       free(path);
+       /* lockpath is shared amongst all non-fork()ing recursive calls to
+        * ls_get() so only free it on the uppermost level. */
+       if (lvl == 0)
+               free(*lockpath);
+
+       return ret;
+}
+
+static char *ls_get_cgroup_item(struct lxc_container *c, const char *item)
+{
+       size_t len = c->get_cgroup_item(c, item, NULL, 0);
+       if (len <= 0)
+               return NULL;
+
+       char *val = malloc((len + 1) * sizeof(*val));
+       if (!val)
+               return NULL;
+
+       if ((size_t)c->get_cgroup_item(c, item, val, len + 1) != len) {
+               free(val);
+               val = NULL;
+       }
+
+       return val;
+}
+
+static char *ls_get_groups(struct lxc_container *c, bool running)
+{
+       size_t len = 0;
+       char *val = NULL;
+
+       if (running)
+               val = c->get_running_config_item(c, "lxc.group");
+       else
+               len = c->get_config_item(c, "lxc.group", NULL, 0);
+
+       if (!val && (len > 0)) {
+               val = malloc((len + 1) * sizeof(*val));
+               if ((size_t)c->get_config_item(c, "lxc.group", val, len + 1) != len) {
+                       free(val);
+                       return NULL;
+               }
+       }
+
+       if (val) {
+               char *tmp;
+               if ((tmp = strrchr(val, '\n')))
+                       *tmp = '\0';
+
+               tmp = lxc_string_replace("\n", ", ", val);
+               free(val);
+               val = tmp;
+       }
+
+       return val;
+}
+
+static char *ls_get_ips(struct lxc_container *c, const char *inet)
+{
+       char *ips = NULL;
+       char **iptmp = c->get_ips(c, NULL, inet, 0);
+       if (iptmp)
+               ips = lxc_string_join(", ", (const char **)iptmp, false);
+
+       lxc_free_array((void **)iptmp, free);
+
+       return ips;
+}
+
+static char *ls_get_interface(struct lxc_container *c)
+{
+       char **interfaces = c->get_interfaces(c);
+       if (!interfaces)
+               return NULL;
+
+       char *interface = lxc_string_join(", ", (const char **)interfaces, false);
+
+       lxc_free_array((void **)interfaces, free);
+
+       return interface;
+}
+
+/*
+ * To calculate swap usage we should not simply check memory.usage_in_bytes and
+ * memory.memsw.usage_in_bytes and then do:
+ *     swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
+ * because we might receive an incorrect/negative value.
+ * Instead we check memory.stat and check the "swap" value.
+ */
+static double ls_get_swap(struct lxc_container *c)
+{
+       unsigned long long int num = 0;
+       char *stat = ls_get_cgroup_item(c, "memory.stat");
+       if (!stat)
+               goto out;
+
+       char *swap = strstr(stat, "\nswap");
+       if (!swap)
+               goto out;
+
+       swap = 1 + swap + 4 + 1; // start_of_swap_value = '\n' + strlen(swap) + ' '
+
+       char *tmp = strchr(swap, '\n'); // find end of swap value
+       if (!tmp)
+               goto out;
+
+       *tmp = '\0';
+
+       num = strtoull(swap, NULL, 0);
+       num = num / 1024 / 1024;
+
+out:
+       free(stat);
+
+       return num;
+}
+
+static unsigned int ls_get_term_width(void)
+{
+       struct winsize ws;
+       if (((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) &&
+            (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1) &&
+            (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)) ||
+           (ws.ws_col == 0))
+               return 0;
+
+       return ws.ws_col;
+}
+
+static bool ls_has_all_grps(const char *has, char **must, size_t must_len)
+{
+       bool bret = false;
+
+       if (!has && must)
+               return false;
+       else if (!must)
+               return true;
+
+       char **tmp_has = lxc_string_split_and_trim(has, ',');
+       size_t tmp_has_len = lxc_array_len((void **)tmp_has);
+
+       /* Don't do any unnecessary work. */
+       if (must_len > tmp_has_len)
+               goto out;
+
+       size_t i, j;
+       for (i = 0; i < must_len; i++) {
+               for (j = 0; j < tmp_has_len; j++)
+                       if (strcmp(must[i], tmp_has[j]) == 0)
+                               break;
+               if (j == tmp_has_len)
+                       break;
+       }
+       if (i == must_len)
+               bret = true;
+
+out:
+       lxc_free_array((void **)tmp_has, free);
+
+       return bret;
+}
+
+static struct ls *ls_new(struct ls **ls, size_t *size)
+{
+       struct ls *m, *n;
+
+       n = realloc(*ls, (*size + 1) * sizeof(struct ls));
+       if (!n)
+               return NULL;
+
+       *ls = n;
+       m = *ls + *size;
+       (*size)++;
+
+       *m = (struct ls){.name = NULL, .init = -1};
+
+       return m;
+}
+
+static void ls_print_names(struct ls *l, struct lengths *lht,
+               size_t size, size_t termwidth)
+{
+       /* If list is empty do nothing. */
+       if (size == 0)
+               return;
+
+       size_t i, len = 0;
+       struct ls *m = NULL;
+       for (i = 0, m = l; i < size; i++, m++) {
+               printf("%-*s", lht->name_length, m->name ? m->name : "-");
+               len += lht->name_length;
+               if ((len + lht->name_length) >= termwidth) {
+                       printf("\n");
+                       len = 0;
+               } else {
+                       printf(" ");
+                       len++;
+               }
+       }
+       if (len > 0)
+               printf("\n");
+}
+
+static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
+               size_t size, const char *fancy_fmt)
+{
+       /* If list is empty do nothing. */
+       if (size == 0)
+               return;
+
+       char **tmp = lxc_string_split_and_trim(fancy_fmt, ',');
+       if (!tmp)
+               return;
+
+       char **s;
+       /* Check for invalid keys. */
+       for (s = tmp; s && *s; s++) {
+               if (strcasecmp(*s, "NAME") && strcasecmp(*s, "STATE") &&
+                               strcasecmp(*s, "PID") && strcasecmp(*s, "RAM") &&
+                               strcasecmp(*s, "SWAP") && strcasecmp(*s, "AUTOSTART") &&
+                               strcasecmp(*s, "GROUPS") && strcasecmp(*s, "INTERFACE") &&
+                               strcasecmp(*s, "IPV4") && strcasecmp(*s, "IPV6")) {
+                       fprintf(stderr, "Invalid key: %s\n", *s);
+                       return;
+               }
+       }
+
+       /* print header */
+       for (s = tmp; s && *s; s++) {
+               if (strcasecmp(*s, "NAME") == 0)
+                       printf("%-*s ", lht->name_length, "NAME");
+               else if (strcasecmp(*s, "STATE") == 0)
+                       printf("%-*s ", lht->state_length, "STATE");
+               else if (strcasecmp(*s, "PID") == 0)
+                       printf("%-*s ", lht->init_length, "PID");
+               else if (strcasecmp(*s, "RAM") == 0)
+                       printf("%-*s ", lht->ram_length + 2, "RAM");
+               else if (strcasecmp(*s, "SWAP") == 0)
+                       printf("%-*s ", lht->swap_length + 2, "SWAP");
+               else if (strcasecmp(*s, "AUTOSTART") == 0)
+                       printf("%-*s ", lht->autostart_length, "AUTOSTART");
+               else if (strcasecmp(*s, "GROUPS") == 0)
+                       printf("%-*s ", lht->groups_length, "GROUPS");
+               else if (strcasecmp(*s, "INTERFACE") == 0)
+                       printf("%-*s ", lht->interface_length, "INTERFACE");
+               else if (strcasecmp(*s, "IPV4") == 0)
+                       printf("%-*s ", lht->ipv4_length, "IPV4");
+               else if (strcasecmp(*s, "IPV6") == 0)
+                       printf("%-*s ", lht->ipv6_length, "IPV6");
+       }
+       printf("\n");
+
+       struct ls *m = NULL;
+       size_t i;
+       for (i = 0, m = l; i < size; i++, m++) {
+               for (s = tmp; s && *s; s++) {
+                       if (strcasecmp(*s, "NAME") == 0) {
+                               if (m->nestlvl > 0) {
+                                       printf("%*s", m->nestlvl, "\\");
+                                       printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
+                               } else {
+                                       printf("%-*s ", lht->name_length, m->name ? m->name : "-");
+                               }
+                       } else if (strcasecmp(*s, "STATE") == 0) {
+                               printf("%-*s ", lht->state_length, m->state ? m->state : "-");
+                       } else if (strcasecmp(*s, "PID") == 0) {
+                               if (m->init > 0)
+                                       printf("%-*d ", lht->init_length, m->init);
+                               else
+                                       printf("%-*s ", lht->init_length, "-");
+                       } else if (strcasecmp(*s, "RAM") == 0) {
+                               if ((m->ram >= 0) && m->running)
+                                       printf("%*.2fMB ", lht->ram_length, m->ram);
+                               else
+                                       printf("%-*s   ", lht->ram_length, "-");
+                       } else if (strcasecmp(*s, "SWAP") == 0) {
+                               if ((m->swap >= 0) && m->running)
+                                       printf("%*.2fMB ", lht->swap_length, m->swap);
+                               else
+                                       printf("%-*s   ", lht->swap_length, "-");
+                       } else if (strcasecmp(*s, "AUTOSTART") == 0) {
+                               printf("%-*d ", lht->autostart_length, m->autostart);
+                       } else if (strcasecmp(*s, "GROUPS") == 0) {
+                               printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
+                       } else if (strcasecmp(*s, "INTERFACE") == 0) {
+                               printf("%-*s ", lht->interface_length, m->interface ? m->interface : "-");
+                       } else if (strcasecmp(*s, "IPV4") == 0) {
+                               printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
+                       } else if (strcasecmp(*s, "IPV6") == 0) {
+                               printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
+                       }
+               }
+               printf("\n");
+       }
+}
+
+static void ls_print_table(struct ls *l, struct lengths *lht,
+               size_t size)
+{
+       /* If list is empty do nothing. */
+       if (size == 0)
+               return;
+
+       struct ls *m = NULL;
+
+       /* print header */
+       printf("%-*s ", lht->name_length, "NAME");
+       printf("%-*s ", lht->state_length, "STATE");
+       printf("%-*s ", lht->autostart_length, "AUTOSTART");
+       printf("%-*s ", lht->groups_length, "GROUPS");
+       printf("%-*s ", lht->ipv4_length, "IPV4");
+       printf("%-*s ", lht->ipv6_length, "IPV6");
+       printf("\n");
+
+       size_t i;
+       for (i = 0, m = l; i < size; i++, m++) {
+               if (m->nestlvl > 0) {
+                       printf("%*s", m->nestlvl, "\\");
+                       printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
+               } else {
+                    printf("%-*s ", lht->name_length, m->name ? m->name : "-");
+               }
+               printf("%-*s ", lht->state_length, m->state ? m->state : "-");
+               printf("%-*d ", lht->autostart_length, m->autostart);
+               printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
+               printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
+               printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
+               printf("\n");
+       }
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+       char *invalid;
+       unsigned long int m, n = MAX_NESTLVL;
+       switch (c) {
+       case '1':
+               args->ls_line = true;
+               break;
+       case 'f':
+               args->ls_fancy = true;
+               break;
+       case LS_ACTIVE:
+               args->ls_active = true;
+               break;
+       case LS_FROZEN:
+               args->ls_frozen = true;
+               break;
+       case LS_RUNNING:
+               args->ls_running = true;
+               break;
+       case LS_STOPPED:
+               args->ls_stopped = true;
+               break;
+       case LS_NESTING:
+               /* In case strtoul() receives a string that represents a
+                * negative number it will return ULONG_MAX - the number that
+                * the string represents if the number the string represents is
+                * < ULONG_MAX and ULONG_MAX otherwise. But it will consider
+                * this valid input and not set errno. So we check manually if
+                * the first character of num_string == '-'. Otherwise the
+                * default level remains set. */
+               if (arg && !(*arg == '-')) {
+                       errno = 0;
+                       m = strtoul(arg, &invalid, 0);
+                       /* ls_nesting has type unsigned int. */
+                       if (!errno && (*invalid == '\0') && (m <= UINT_MAX))
+                               n = m;
+               }
+               args->ls_nesting = n;
+               break;
+       case 'g':
+               args->groups = arg;
+               break;
+       case LS_FILTER:
+               args->ls_filter = arg;
+               break;
+       case 'F':
+               args->ls_fancy_format = arg;
+               break;
+       }
+
+       return 0;
+}
+
+static int ls_get_wrapper(void *wrap)
+{
+       int ret = -1;
+       size_t len = 0;
+       struct wrapargs *wargs = (struct wrapargs *)wrap;
+       struct ls *m = NULL, *n = NULL;
+
+       /* close pipe */
+       close(wargs->pipefd[0]);
+
+       /* &(char *){NULL} is no magic. It's just a compound literal which
+        * allows us to avoid keeping a pointless variable around. */
+       ls_get(&m, &len, wargs->args, "", wargs->parent, wargs->nestlvl, &(char *){NULL}, 0, wargs->grps_must, wargs->grps_must_len);
+       if (!m)
+               goto out;
+
+       /* send length */
+       if (lxc_write_nointr(wargs->pipefd[1], &len, sizeof(len)) <= 0)
+               goto out;
+
+       size_t i;
+       for (i = 0, n = m; i < len; i++, n++) {
+               if (ls_serialize(wargs->pipefd[1], n) == -1)
+                       goto out;
+       }
+       ret = 0;
+
+out:
+       shutdown(wargs->pipefd[1], SHUT_RDWR);
+       close(wargs->pipefd[1]);
+       ls_free(m, len);
+
+       return ret;
+}
+
+static int ls_remove_lock(const char *path, const char *name,
+               char **lockpath, size_t *len_lockpath, bool recalc)
+{
+       /* Avoid doing unnecessary work if we can. */
+       if (recalc) {
+               size_t newlen = strlen(path) + strlen(name) + strlen(RUNTIME_PATH) + /* / + lxc + / + lock + / + / = */ 11 + 1;
+               if (newlen > *len_lockpath) {
+                       char *tmp = realloc(*lockpath, newlen * 2);
+                       if (!tmp)
+                               return -1;
+                       *lockpath = tmp;
+                       *len_lockpath = newlen * 2;
+               }
+       }
+
+       int check = snprintf(*lockpath, *len_lockpath, "%s/lxc/lock/%s/%s", RUNTIME_PATH, path, name);
+       if (check < 0 || (size_t)check >= *len_lockpath)
+               return -1;
+
+       lxc_rmdir_onedev(*lockpath, NULL);
+
+       return 0;
+}
+
+static int ls_serialize(int wpipefd, struct ls *n)
+{
+       ssize_t nbytes = sizeof(n->ram);
+       if (lxc_write_nointr(wpipefd, &n->ram, nbytes) != nbytes)
+               return -1;
+
+       nbytes = sizeof(n->swap);
+       if (lxc_write_nointr(wpipefd, &n->swap, nbytes) != nbytes)
+               return -1;
+
+       nbytes = sizeof(n->init);
+       if (lxc_write_nointr(wpipefd, &n->init, nbytes) != nbytes)
+               return -1;
+
+       nbytes = sizeof(n->autostart);
+       if (lxc_write_nointr(wpipefd, &n->autostart, nbytes) != nbytes)
+               return -1;
+
+       nbytes = sizeof(n->running);
+       if (lxc_write_nointr(wpipefd, &n->running, nbytes) != nbytes)
+               return -1;
+
+       nbytes = sizeof(n->nestlvl);
+       if (lxc_write_nointr(wpipefd, &n->nestlvl, nbytes) != nbytes)
+               return -1;
+
+       if (ls_write(wpipefd, "NAME:", 5 + 1, n->name) == -1)
+               return -1;
+
+       if (ls_write(wpipefd, "STATE:", 6 + 1, n->state) == -1)
+               return -1;
+
+       if (ls_write(wpipefd, "GROUPS:", 7 + 1, n->groups) == -1)
+               return -1;
+
+       if (ls_write(wpipefd, "INTERFACE:", 10 + 1, n->interface) == -1)
+               return -1;
+
+       if (ls_write(wpipefd, "IPV4:", 5 + 1, n->ipv4) == -1)
+               return -1;
+
+       if (ls_write(wpipefd, "IPV6:", 5 + 1, n->ipv6) == -1)
+               return -1;
+
+       return 0;
+}
+
+static int ls_write(const int wpipefd, const char *id, ssize_t nbytes_id,
+               const char *s)
+{
+       if (lxc_write_nointr(wpipefd, id, nbytes_id) != nbytes_id)
+               return -1;
+       if (s) {
+               nbytes_id = strlen(s) + 1;
+               if (lxc_write_nointr(wpipefd, s, nbytes_id) != nbytes_id)
+                       return -1;
+       } else {
+               if (lxc_write_nointr(wpipefd, "\0", 1) != 1)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int ls_deserialize(int rpipefd, struct ls **m, size_t *len)
+{
+       struct ls *n;
+       size_t sublen = 0;
+       ssize_t nbytes = 0;
+       int ret = -1;
+
+       /* get length */
+       nbytes = sizeof(sublen);
+       if (lxc_read_nointr(rpipefd, &sublen, nbytes) != nbytes)
+               return -1;
+
+       char *serialized = NULL;
+       serialized = malloc(LINELEN * sizeof(char));
+       if (!serialized)
+               return -1;
+
+       while (sublen-- > 0) {
+               n = ls_new(m, len);
+               if (!n)
+                       goto out;
+
+               nbytes = sizeof(n->ram);
+               if (lxc_read_nointr(rpipefd, &n->ram, nbytes) != nbytes)
+                       goto out;
+
+               nbytes = sizeof(n->swap);
+               if (lxc_read_nointr(rpipefd, &n->swap, nbytes) != nbytes)
+                       goto out;
+
+               nbytes = sizeof(n->init);
+               if (lxc_read_nointr(rpipefd, &n->init, nbytes) != nbytes)
+                       goto out;
+
+               nbytes = sizeof(n->autostart);
+               if (lxc_read_nointr(rpipefd, &n->autostart, nbytes) != nbytes)
+                       goto out;
+
+               nbytes = sizeof(n->running);
+               if (lxc_read_nointr(rpipefd, &n->running, nbytes) != nbytes)
+                       goto out;
+
+               nbytes = sizeof(n->nestlvl);
+               if (lxc_read_nointr(rpipefd, &n->nestlvl, nbytes) != nbytes)
+                       goto out;
+
+               ssize_t buf_size = LINELEN;
+               if (ls_read_and_grow_buf(rpipefd, &n->name, "NAME:", 5 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+
+               if (ls_read_and_grow_buf(rpipefd, &n->state, "STATE:", 6 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+
+               if (ls_read_and_grow_buf(rpipefd, &n->groups, "GROUPS:", 7 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+
+               if (ls_read_and_grow_buf(rpipefd, &n->interface, "INTERFACE:", 10 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+
+               if (ls_read_and_grow_buf(rpipefd, &n->ipv4, "IPV4:", 5 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+
+               if (ls_read_and_grow_buf(rpipefd, &n->ipv6, "IPV6:", 5 + 1, &serialized, &buf_size) == -1)
+                       goto out;
+       }
+       ret = 0;
+
+out:
+       free(serialized);
+
+       return ret;
+}
+
+static int ls_read_and_grow_buf(const int rpipefd, char **save_buf,
+               const char *id, ssize_t nbytes_id,
+               char **read_buf, ssize_t *read_buf_len)
+{
+       char *inc, *tmp;
+       char buf[80]; /* id can only be 79 + \0 long */
+
+       if (lxc_read_nointr(rpipefd, buf, nbytes_id) != nbytes_id)
+               return -1;
+
+       if (strcmp(id, buf) != 0)
+               return -1;
+
+       inc = *read_buf;
+       nbytes_id = 0;
+       do {
+               /* if the next read would overflow our buffer realloc */
+               if (nbytes_id + 1 >= *read_buf_len) {
+                       *read_buf_len += LINELEN;
+                       tmp = realloc(*read_buf, *read_buf_len);
+                       if (!tmp)
+                               return -1;
+                       *read_buf = tmp;
+                       /* Put inc back to where it was before the realloc so we
+                        * can keep on reading in the string. */
+                       inc = *read_buf + nbytes_id;
+               }
+               /* only read one byte at a time */
+               if (lxc_read_nointr(rpipefd, inc, 1) != 1)
+                       return -1;
+               nbytes_id++;
+       } while (*inc++ != '\0');
+
+       if (nbytes_id > 1) {
+               /* save it where the caller wants it */
+               *save_buf = strdup(*read_buf);
+               if (!*save_buf)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void ls_field_width(const struct ls *l, const size_t size,
+               struct lengths *lht)
+{
+       const struct ls *m;
+       size_t i, len = 0;
+       for (i = 0, m = l; i < size; i++, m++) {
+               if (m->name) {
+                       len = strlen(m->name) + m->nestlvl;
+                       if (len > lht->name_length)
+                               lht->name_length = len;
+               }
+
+               if (m->state) {
+                       len = strlen(m->state);
+                       if (len > lht->state_length)
+                               lht->state_length = len;
+               }
+
+               if (m->interface) {
+                       len = strlen(m->interface);
+                       if (len > lht->interface_length)
+                               lht->interface_length = len;
+               }
+
+               if (m->groups) {
+                       len = strlen(m->groups);
+                       if (len > lht->groups_length)
+                               lht->groups_length = len;
+               }
+               if (m->ipv4) {
+                       len = strlen(m->ipv4);
+                       if (len > lht->ipv4_length)
+                               lht->ipv4_length = len;
+               }
+
+               if (m->ipv6) {
+                       len = strlen(m->ipv6);
+                       if (len > lht->ipv6_length)
+                               lht->ipv6_length = len;
+               }
+
+               if ((len = snprintf(NULL, 0, "%.2f", m->ram)) > lht->ram_length)
+                       lht->ram_length = len;
+
+               if ((len = snprintf(NULL, 0, "%.2f", m->swap)) > lht->swap_length)
+                       lht->swap_length = len;
+
+               if (m->init != -1) {
+                       if ((len = snprintf(NULL, 0, "%d", m->init)) > lht->init_length)
+                               lht->init_length = len;
+               }
+       }
+}
index a03c0c0..147101e 100644 (file)
@@ -16,8 +16,8 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include "config.h"
 
+#include "confile.h"
 #include <stdio.h>
 #include <libgen.h>
 #include <unistd.h>
 
 #include "lxc.h"
 #include "log.h"
-#include "bdev.h"
+#include "bdev/bdev.h"
 #include "arguments.h"
 #include "utils.h"
 
 lxc_log_define(lxc_snapshot_ui, lxc);
 
-static char *newname;
-static char *snapshot;
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
 
-#define DO_SNAP 0
-#define DO_LIST 1
-#define DO_RESTORE 2
-#define DO_DESTROY 3
-static int action;
-static int print_comments;
-static char *commentfile;
+static const struct option my_longopts[] = {
+       {"list", no_argument, 0, 'L'},
+       {"restore", required_argument, 0, 'r'},
+       {"newname", required_argument, 0, 'N'},
+       {"destroy", required_argument, 0, 'd'},
+       {"comment", required_argument, 0, 'c'},
+       {"showcomments", no_argument, 0, 'C'},
+       LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+       .progname = "lxc-snapshot",
+       .help = "\
+--name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\
+\n\
+lxc-snapshot snapshots a container\n\
+\n\
+Options :\n\
+  -n, --name=NAME       NAME of the container\n\
+  -L, --list             list all snapshots\n\
+  -r, --restore=NAME     restore snapshot NAME, e.g. 'snap0'\n\
+  -N, --newname=NEWNAME  NEWNAME for the restored container\n\
+  -d, --destroy=NAME     destroy snapshot NAME, e.g. 'snap0'\n\
+                         use ALL to destroy all snapshots\n\
+  -c, --comment=FILE     add FILE as a comment\n\
+  -C, --showcomments     show snapshot comments\n",
+       .options = my_longopts,
+       .parser = my_parser,
+       .checker = NULL,
+       .task = SNAP,
+};
+
+static int do_snapshot(struct lxc_container *c, char *commentfile);
+static int do_snapshot_destroy(struct lxc_container *c, char *snapname);
+static int do_snapshot_list(struct lxc_container *c, int print_comments);
+static int do_snapshot_restore(struct lxc_container *c,
+                              struct lxc_arguments *args);
+static int do_snapshot_task(struct lxc_container *c, enum task task);
+static void print_file(char *path);
+
+int main(int argc, char *argv[])
+{
+       struct lxc_container *c;
+       int ret;
+
+       if (lxc_arguments_parse(&my_args, argc, argv))
+               exit(EXIT_FAILURE);
+
+       if (!my_args.log_file)
+               my_args.log_file = "none";
+
+       if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+                        my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+               exit(EXIT_FAILURE);
+       lxc_log_options_no_override();
+
+       if (geteuid()) {
+               if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+                       fprintf(stderr, "You lack access to %s\n",
+                               my_args.lxcpath[0]);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+       if (!c) {
+               fprintf(stderr, "System error loading container\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!c->may_control(c)) {
+               fprintf(stderr, "Insufficent privileges to control %s\n",
+                       my_args.name);
+               lxc_container_put(c);
+               exit(EXIT_FAILURE);
+       }
+
+       ret = do_snapshot_task(c, my_args.task);
 
-static int do_snapshot(struct lxc_container *c)
+       lxc_container_put(c);
+
+       if (ret == 0)
+               exit(EXIT_SUCCESS);
+       exit(EXIT_FAILURE);
+}
+
+static int do_snapshot_task(struct lxc_container *c, enum task task)
+{
+       int ret = 0;
+
+       switch (task) {
+       case DESTROY:
+               ret = do_snapshot_destroy(c, my_args.snapname);
+               break;
+       case LIST:
+               ret = do_snapshot_list(c, my_args.print_comments);
+               break;
+       case RESTORE:
+               ret = do_snapshot_restore(c, &my_args);
+               break;
+       case SNAP:
+               ret = do_snapshot(c, my_args.commentfile);
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+       switch (c) {
+       case 'L':
+               args->task = LIST;
+               break;
+       case 'r':
+               args->task = RESTORE;
+               args->snapname = arg;
+               break;
+       case 'N':
+               args->newname = arg;
+               break;
+       case 'd':
+               args->task = DESTROY;
+               args->snapname = arg;
+               break;
+       case 'c':
+               args->commentfile = arg;
+               break;
+       case 'C':
+               args->print_comments = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int do_snapshot(struct lxc_container *c, char *commentfile)
 {
        int ret;
 
@@ -57,26 +187,28 @@ static int do_snapshot(struct lxc_container *c)
        }
 
        INFO("Created snapshot snap%d", ret);
+
        return 0;
 }
 
-static void print_file(char *path)
+static int do_snapshot_destroy(struct lxc_container *c, char *snapname)
 {
-       if (!path)
-               return;
-       FILE *f = fopen(path, "r");
-       char *line = NULL;
-       size_t sz = 0;
-       if (!f)
-               return;
-       while (getline(&line, &sz, f) != -1) {
-               printf("%s", line);
+       bool ret;
+
+       if (strcmp(snapname, "ALL") == 0)
+               ret = c->snapshot_destroy_all(c);
+       else
+               ret = c->snapshot_destroy(c, snapname);
+
+       if (!ret) {
+               ERROR("Error destroying snapshot %s", snapname);
+               return -1;
        }
-       free(line);
-       fclose(f);
+
+       return 0;
 }
 
-static int do_list_snapshots(struct lxc_container *c)
+static int do_snapshot_list(struct lxc_container *c, int print_comments)
 {
        struct lxc_snapshot *s;
        int i, n;
@@ -90,148 +222,63 @@ static int do_list_snapshots(struct lxc_container *c)
                printf("No snapshots\n");
                return 0;
        }
-       for (i=0; i<n; i++) {
+
+       for (i = 0; i < n; i++) {
                printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
                if (print_comments)
                        print_file(s[i].comment_pathname);
                s[i].free(&s[i]);
        }
-       free(s);
-       return 0;
-}
 
-static int do_restore_snapshots(struct lxc_container *c)
-{
-       if (c->snapshot_restore(c, snapshot, newname))
-               return 0;
+       free(s);
 
-       ERROR("Error restoring snapshot %s", snapshot);
-       return -1;
+       return 0;
 }
 
-static int do_destroy_snapshots(struct lxc_container *c)
+static int do_snapshot_restore(struct lxc_container *c,
+                              struct lxc_arguments *args)
 {
-       bool bret;
-       if (strcmp(snapshot, "ALL") == 0)
-               bret = c->snapshot_destroy_all(c);
-       else
-               bret = c->snapshot_destroy(c, snapshot);
+       int bret;
+
+       /* When restoring  a snapshot, the last optional argument if not given
+        * explicitly via the corresponding command line option is the name to
+        * use for the restored container. If no name is given, then the
+        * original container will be destroyed and the restored container will
+        * take its place. */
+       if ((!args->newname) && (args->argc > 1)) {
+               lxc_error(args, "Too many arguments");
+               return -1;
+       }
 
-       if (bret)
-               return 0;
+       if ((!args->newname) && (args->argc == 1))
+               args->newname = args->argv[0];
 
-       ERROR("Error destroying snapshot %s", snapshot);
-       return -1;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-       switch (c) {
-       case 'L': action = DO_LIST; break;
-       case 'r': snapshot = arg; action = DO_RESTORE; break;
-       case 'd': snapshot = arg; action = DO_DESTROY; break;
-       case 'c': commentfile = arg; break;
-       case 'C': print_comments = true; break;
+       bret = c->snapshot_restore(c, args->snapname, args->newname);
+       if (!bret) {
+               ERROR("Error restoring snapshot %s", args->snapname);
+               return -1;
        }
+
        return 0;
 }
 
-static const struct option my_longopts[] = {
-       {"list", no_argument, 0, 'L'},
-       {"restore", required_argument, 0, 'r'},
-       {"destroy", required_argument, 0, 'd'},
-       {"comment", required_argument, 0, 'c'},
-       {"showcomments", no_argument, 0, 'C'},
-       LXC_COMMON_OPTIONS
-};
-
-
-static struct lxc_arguments my_args = {
-       .progname = "lxc-snapshot",
-       .help     = "\
---name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [newname]]\n\
-\n\
-lxc-snapshot snapshots a container\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME for name of the container\n\
-  -L, --list          list snapshots\n\
-  -C, --showcomments  show snapshot comments in list\n\
-  -c, --comment=file  add file as a comment\n\
-  -r, --restore=name  restore snapshot name, i.e. 'snap0'\n\
-  -d, --destroy=name  destroy snapshot name, i.e. 'snap0'\n\
-                      use ALL to destroy all snapshots\n",
-       .options  = my_longopts,
-       .parser   = my_parser,
-       .checker  = NULL,
-};
-
-/*
- * lxc-snapshot -P lxcpath -n container
- * lxc-snapshot -P lxcpath -n container -l
- * lxc-snapshot -P lxcpath -n container -r snap3 recovered_1
- */
-
-int main(int argc, char *argv[])
+static void print_file(char *path)
 {
-       struct lxc_container *c;
-       int ret = 0;
-
-       if (lxc_arguments_parse(&my_args, argc, argv))
-               exit(1);
-
-       if (!my_args.log_file)
-               my_args.log_file = "none";
-
-       if (my_args.argc > 1) {
-               ERROR("Too many arguments");
-               exit(1);
-       }
-       if (my_args.argc == 1)
-               newname = my_args.argv[0];
-
-       if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-                        my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-               exit(1);
-       lxc_log_options_no_override();
-
-       if (geteuid()) {
-               if (access(my_args.lxcpath[0], O_RDWR) < 0) {
-                       fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
-                       exit(1);
-               }
-       }
+       if (!path)
+               return;
 
-       c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-       if (!c) {
-               fprintf(stderr, "System error loading container\n");
-               exit(1);
-       }
+       FILE *f = fopen(path, "r");
+       char *line = NULL;
+       size_t sz = 0;
 
-       if (!c->may_control(c)) {
-               fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
-               lxc_container_put(c);
-               exit(1);
-       }
+       if (!f)
+               return;
 
-       switch(action) {
-       case DO_SNAP:
-               ret = do_snapshot(c);
-               break;
-       case DO_LIST:
-               ret = do_list_snapshots(c);
-               break;
-       case DO_RESTORE:
-               ret = do_restore_snapshots(c);
-               break;
-       case DO_DESTROY:
-               ret = do_destroy_snapshots(c);
-               break;
+       while (getline(&line, &sz, f) != -1) {
+               printf("%s", line);
        }
 
-       lxc_container_put(c);
-
-       if (ret == 0)
-               exit(EXIT_SUCCESS);
-       exit(EXIT_FAILURE);
+       free(line);
+       fclose(f);
 }
+
index 8501461..c4cb871 100644 (file)
@@ -114,6 +114,7 @@ Options :\n\
 static void stdin_tios_restore(void)
 {
        tcsetattr(0, TCSAFLUSH, &oldtios);
+       fprintf(stderr, "\n");
 }
 
 static int stdin_tios_setup(void)
@@ -281,12 +282,12 @@ static void stats_get(struct lxc_container *c, struct ct *ct, struct stats *tota
 static void stats_print_header(struct stats *stats)
 {
        printf(TERMRVRS TERMBOLD);
-       printf("%-18s %8s %8s %8s %10s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem");
+       printf("%-18s %12s %12s %12s %14s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem");
        if (stats->kmem_used > 0)
                printf(" %10s", "KMem");
        printf("\n");
 
-       printf("%-18s %8s %8s %8s %10s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used");
+       printf("%-18s %12s %12s %12s %14s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used");
        if (stats->kmem_used > 0)
                printf(" %10s", "Used");
        printf("\n");
@@ -303,7 +304,7 @@ static void stats_print(const char *name, const struct stats *stats,
        size_humanize(stats->blkio, blkio_str, sizeof(blkio_str));
        size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str));
 
-       printf("%-18.18s %8.2f %8.2f %8.2f %10s %10s",
+       printf("%-18.18s %12.2f %12.2f %12.2f %14s %10s",
               name,
               (float)stats->cpu_use_nanos / 1000000000,
               (float)stats->cpu_use_sys  / USER_HZ,
index 6622db0..87780ca 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdbool.h>
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/file.h>
 
 static void usage(char *me, bool fail)
 {
-       fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
+       fprintf(stderr, "Usage: %s lxcpath name pid type bridge nicname\n", me);
        fprintf(stderr, " nicname is the name to use inside the container\n");
        exit(fail ? 1 : 0);
 }
 
+static char *lxcpath, *lxcname;
+
 static int open_and_lock(char *path)
 {
        int fd;
@@ -96,20 +99,175 @@ static char *get_username(void)
        return pwd->pw_name;
 }
 
+static void free_groupnames(char **groupnames)
+{
+       int i;
+       if (!groupnames)
+               return;
+       for (i = 0; groupnames[i]; i++)
+               free(groupnames[i]);
+       free(groupnames);
+}
+
+static char **get_groupnames(void)
+{
+       int ngroups;
+       gid_t *group_ids;
+       int ret, i;
+       char **groupnames;
+       struct group *gr;
+
+       ngroups = getgroups(0, NULL);
+
+       if (ngroups == -1) {
+               fprintf(stderr, "Failed to get number of groups user belongs to: %s\n", strerror(errno));
+               return NULL;
+       }
+       if (ngroups == 0)
+               return NULL;
+
+       group_ids = (gid_t *)malloc(sizeof(gid_t)*ngroups);
+
+       if (group_ids == NULL) {
+               fprintf(stderr, "Out of memory while getting groups the user belongs to\n");
+               return NULL;
+       }
+
+       ret = getgroups(ngroups, group_ids);
+
+       if (ret < 0) {
+               free(group_ids);
+               fprintf(stderr, "Failed to get process groups: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       groupnames = (char **)malloc(sizeof(char *)*(ngroups+1));
+
+       if (groupnames == NULL) {
+               free(group_ids);
+               fprintf(stderr, "Out of memory while getting group names\n");
+               return NULL;
+       }
+
+       memset(groupnames, 0, sizeof(char *)*(ngroups+1));
+
+       for (i=0; i<ngroups; i++ ) {
+               gr = getgrgid(group_ids[i]);
+
+               if (gr == NULL) {
+                       fprintf(stderr, "Failed to get group name\n");
+                       free(group_ids);
+                       free_groupnames(groupnames);
+                       return NULL;
+               }
+
+               groupnames[i] = strdup(gr->gr_name);
+
+               if (groupnames[i] == NULL) {
+                       fprintf(stderr, "Failed to copy group name: %s", gr->gr_name);
+                       free(group_ids);
+                       free_groupnames(groupnames);
+                       return NULL;
+               }
+       }
+
+       free(group_ids);
+
+       return groupnames;
+}
+
+static bool name_is_in_groupnames(char *name, char **groupnames)
+{
+       while (groupnames != NULL) {
+               if (strcmp(name, *groupnames) == 0)
+                       return true;
+               groupnames++;
+       }
+       return false;
+}
+
+struct alloted_s {
+       char *name;
+       int allowed;
+       struct alloted_s *next;
+};
+
+static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n)
+{
+       struct alloted_s *cur, *al;
+
+       if (head == NULL || name == NULL) {
+               // sanity check. parameters should not be null
+               fprintf(stderr, "NULL parameters to append_alloted not allowed\n");
+               return NULL;
+       }
+
+       al = (struct alloted_s *)malloc(sizeof(struct alloted_s));
+
+       if (al == NULL) {
+               // unable to allocate memory to new struct
+               fprintf(stderr, "Out of memory in append_alloted\n");
+               return NULL;
+       }
+
+       al->name = strdup(name);
+
+       if (al->name == NULL) {
+               free(al);
+               return NULL;
+       }
+
+       al->allowed = n;
+       al->next = NULL;
+
+       if (*head == NULL) {
+               *head = al;
+               return al;
+       }
+
+       cur = *head;
+       while (cur->next != NULL)
+               cur = cur->next;
+
+       cur->next = al;
+       return al;
+}
+
+static void free_alloted(struct alloted_s **head)
+{
+       struct alloted_s *cur;
+
+       if (head == NULL) {
+               return;
+       }
+
+       cur = *head;
+
+       while (cur != NULL) {
+               cur = cur->next;
+               free((*head)->name);
+               free(*head);
+               *head = cur;
+       }
+}
+
 /* The configuration file consists of lines of the form:
  *
  * user type bridge count
+ * or
+ * @group type bridge count
  *
  * Return the count entry for the calling user if there is one.  Else
  * return -1.
  */
-static int get_alloted(char *me, char *intype, char *link)
+static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted)
 {
        FILE *fin = fopen(LXC_USERNIC_CONF, "r");
        char *line = NULL;
-       char user[100], type[100], br[100];
+       char name[100], type[100], br[100];
        size_t len = 0;
-       int n = -1, ret;
+       int n, ret, count = 0;
+       char **groups;
 
        if (!fin) {
                fprintf(stderr, "Failed to open %s: %s\n", LXC_USERNIC_CONF,
@@ -117,24 +275,48 @@ static int get_alloted(char *me, char *intype, char *link)
                return -1;
        }
 
+       groups = get_groupnames();
        while ((getline(&line, &len, fin)) != -1) {
-               ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", user, type, br, &n);
+               ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
 
                if (ret != 4)
                        continue;
-               if (strcmp(user, me) != 0)
+
+               if (strlen(name) == 0)
                        continue;
+
+               if (strcmp(name, me) != 0)
+               {
+                       if (name[0] != '@')
+                               continue;
+                       if (!name_is_in_groupnames(name+1, groups))
+                               continue;
+               }
                if (strcmp(type, intype) != 0)
                        continue;
                if (strcmp(link, br) != 0)
                        continue;
-               free(line);
-               fclose(fin);
-               return n;
+
+               /* found the user or group with the appropriate settings, therefore finish the search.
+                * what to do if there are more than one applicable lines? not specified in the docs.
+                * since getline is implemented with realloc, we don't need to free line until exiting func.
+                *
+                * if append_alloted returns NULL, e.g. due to a malloc error, we set count to 0 and break the loop,
+                * allowing cleanup and then exiting from main()
+                */
+               if (append_alloted(alloted, name, n) == NULL) {
+                       count = 0;
+                       break;
+               }
+               count += n;
        }
+
+       free_groupnames(groups);
        fclose(fin);
        free(line);
-       return -1;
+
+       // now return the total number of nics that this user can create
+       return count;
 }
 
 static char *get_eol(char *s, char *e)
@@ -154,7 +336,7 @@ static char *get_eow(char *s, char *e)
 static char *find_line(char *p, char *e, char *u, char *t, char *l)
 {
        char *p1, *p2, *ret;
-       
+
        while (p<e  && (p1 = get_eol(p, e)) < e) {
                ret = p;
                if (*p == '#')
@@ -187,6 +369,8 @@ static bool nic_exists(char *nic)
        int ret;
        struct stat sb;
 
+       if (strcmp(nic, "none") == 0)
+               return true;
        ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
        if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
                return false;
@@ -250,20 +434,22 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
                return false;
        }
 
-       /* copy the bridge's mtu to both ends */
-       mtu = get_mtu(br);
-       if (mtu != -1) {
-               if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
-                               lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
-                       fprintf(stderr, "Failed setting mtu\n");
-                       goto out_del;
+       if (strcmp(br, "none") != 0) {
+               /* copy the bridge's mtu to both ends */
+               mtu = get_mtu(br);
+               if (mtu != -1) {
+                       if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
+                                       lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
+                               fprintf(stderr, "Failed setting mtu\n");
+                               goto out_del;
+                       }
                }
-       }
 
-       /* attach veth1 to bridge */
-       if (lxc_bridge_attach(br, veth1buf) < 0) {
-               fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
-               goto out_del;
+               /* attach veth1 to bridge */
+               if (lxc_bridge_attach(lxcpath, lxcname, br, veth1buf) < 0) {
+                       fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
+                       goto out_del;
+               }
        }
 
        /* pass veth2 to target netns */
@@ -357,7 +543,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
                p += entry_lines[n-1].len + 1;
                if (p >= e)
                        break;
-       }
+       }
        p = buf;
        for (i=0; i<n; i++) {
                if (!entry_lines[i].keep)
@@ -392,18 +578,23 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
  * The dbfile has lines of the format:
  * user type bridge nicname
  */
-static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
+static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
 {
        off_t len, slen;
        struct stat sb;
        char *buf = NULL, *newline;
        int ret, count = 0;
+       char *owner;
+       struct alloted_s *n;
 
-       cull_entries(fd, me, intype, br);
+       for (n=names; n!=NULL; n=n->next)
+               cull_entries(fd, n->name, intype, br);
 
        if (allowed == 0)
                return false;
 
+       owner = names->name;
+
        if (fstat(fd, &sb) < 0) {
                fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
                return false;
@@ -416,17 +607,27 @@ static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br,
                        return false;
                }
 
-               count = count_entries(buf, len, me, intype, br);
-               if (count >= allowed)
-                       return false;
+               owner = NULL;
+               for (n=names; n!=NULL; n=n->next) {
+                       count = count_entries(buf, len, n->name, intype, br);
+
+                       if (count >= n->allowed)
+                               continue;
+
+                       owner = n->name;
+                       break;
+               }
        }
 
+       if (owner == NULL)
+               return false;
+
        if (!get_new_nicname(nicname, br, pid, cnic))
                return false;
-       /* me  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
-       slen = strlen(me) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
+       /* owner  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
+       slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
        newline = alloca(slen);
-       ret = snprintf(newline, slen, "%s %s %s %s\n", me, intype, br, *nicname);
+       ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, *nicname);
        if (ret < 0 || ret >= slen) {
                if (lxc_netdev_delete_by_name(*nicname) != 0)
                        fprintf(stderr, "Error unlinking %s!\n", *nicname);
@@ -588,6 +789,7 @@ int main(int argc, char *argv[])
        char *cnic = NULL; // created nic name in container is returned here.
        char *vethname = NULL;
        int pid;
+       struct alloted_s *alloted = NULL;
 
        /* set a sane env, because we are setuid-root */
        if (clearenv() < 0) {
@@ -603,13 +805,16 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       if (argc < 4)
+       if (argc < 6)
                usage(argv[0], true);
-       if (argc >= 5)
-               vethname = argv[4];
+       if (argc >= 7)
+               vethname = argv[6];
+
+       lxcpath = argv[1];
+       lxcname = argv[2];
 
        errno = 0;
-       pid = (int) strtol(argv[1], NULL, 10);
+       pid = (int) strtol(argv[3], NULL, 10);
        if (errno) {
                fprintf(stderr, "Could not read pid: %s\n", argv[1]);
                exit(1);
@@ -627,14 +832,16 @@ int main(int argc, char *argv[])
 
        if (!may_access_netns(pid)) {
                fprintf(stderr, "User %s may not modify netns for pid %d\n",
-                               me, pid);
+                       me, pid);
                exit(1);
        }
 
-       n = get_alloted(me, argv[2], argv[3]);
+       n = get_alloted(me, argv[4], argv[5], &alloted);
        if (n > 0)
-               gotone = get_nic_if_avail(fd, me, pid, argv[2], argv[3], n, &nicname, &cnic);
+               gotone = get_nic_if_avail(fd, alloted, pid, argv[4], argv[5], n, &nicname, &cnic);
+
        close(fd);
+       free_alloted(&alloted);
        if (!gotone) {
                fprintf(stderr, "Quota reached\n");
                exit(1);
index 37d92fb..6745ac3 100644 (file)
@@ -291,7 +291,7 @@ int main(int argc, char *argv[])
                }
                ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2));
                if (ret < 0) {
-                       printf("Warning: unable to open stderr, continueing.");
+                       printf("Warning: unable to open stderr, continuing.");
                        memset(ttyname2, '\0', sizeof(ttyname2));
                }
        }
index 11d1822..9f12ca2 100644 (file)
 
 #define _GNU_SOURCE
 #include <assert.h>
-#include <stdarg.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/mount.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <sched.h>
-#include <dirent.h>
-#include <sched.h>
-#include <arpa/inet.h>
+#include <grp.h>
 #include <libgen.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
 #include <stdint.h>
-#include <grp.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
 #include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
-#include <lxc/lxccontainer.h>
-#include <lxc/version.h>
-#include <lxc/network.h>
-
-#include "config.h"
-#include "lxc.h"
-#include "state.h"
+#include "attach.h"
+#include "bdev/bdev.h"
+#include "bdev/lxcoverlay.h"
+#include "bdev/lxcbtrfs.h"
+#include "cgroup.h"
 #include "conf.h"
+#include "config.h"
+#include "commands.h"
 #include "confile.h"
 #include "console.h"
-#include "cgroup.h"
-#include "commands.h"
 #include "criu.h"
 #include "log.h"
-#include "bdev.h"
-#include "utils.h"
-#include "attach.h"
+#include "lxc.h"
+#include "lxccontainer.h"
+#include "lxclock.h"
 #include "monitor.h"
 #include "namespace.h"
 #include "network.h"
-#include "lxclock.h"
 #include "sync.h"
+#include "state.h"
+#include "utils.h"
+#include "version.h"
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
@@ -173,7 +173,7 @@ static int create_partial(struct lxc_container *c)
                return -1;
        }
        if ((fd=open(path, O_RDWR | O_CREAT | O_EXCL, 0755)) < 0) {
-               SYSERROR("Erorr creating partial file");
+               SYSERROR("Error creating partial file");
                return -1;
        }
        lk.l_type = F_WRLCK;
@@ -344,9 +344,17 @@ out:
 static rettype fnname(struct lxc_container *c)                         \
 {                                                                      \
        rettype ret;                                                    \
-       current_config = c ? c->lxc_conf : NULL;                        \
+       bool reset_config = false;                                      \
+                                                                       \
+       if (!current_config && c && c->lxc_conf) {                      \
+               current_config = c->lxc_conf;                           \
+               reset_config = true;                                    \
+       }                                                               \
+                                                                       \
        ret = do_##fnname(c);                                           \
-       current_config = NULL;                                          \
+       if (reset_config)                                               \
+               current_config = NULL;                                  \
+                                                                       \
        return ret;                                                     \
 }
 
@@ -354,9 +362,17 @@ static rettype fnname(struct lxc_container *c)                             \
 static rettype fnname(struct lxc_container *c, t1 a1)                  \
 {                                                                      \
        rettype ret;                                                    \
-       current_config = c ? c->lxc_conf : NULL;                        \
+       bool reset_config = false;                                      \
+                                                                       \
+       if (!current_config && c && c->lxc_conf) {                      \
+               current_config = c->lxc_conf;                           \
+               reset_config = true;                                    \
+       }                                                               \
+                                                                       \
        ret = do_##fnname(c, a1);                                       \
-       current_config = NULL;                                          \
+       if (reset_config)                                               \
+               current_config = NULL;                                  \
+                                                                       \
        return ret;                                                     \
 }
 
@@ -364,9 +380,17 @@ static rettype fnname(struct lxc_container *c, t1 a1)                      \
 static rettype fnname(struct lxc_container *c, t1 a1, t2 a2)           \
 {                                                                      \
        rettype ret;                                                    \
-       current_config = c ? c->lxc_conf : NULL;                        \
+       bool reset_config = false;                                      \
+                                                                       \
+       if (!current_config && c && c->lxc_conf) {                      \
+               current_config = c->lxc_conf;                           \
+               reset_config = true;                                    \
+       }                                                               \
+                                                                       \
        ret = do_##fnname(c, a1, a2);                                   \
-       current_config = NULL;                                          \
+       if (reset_config)                                               \
+               current_config = NULL;                                  \
+                                                                       \
        return ret;                                                     \
 }
 
@@ -374,9 +398,17 @@ static rettype fnname(struct lxc_container *c, t1 a1, t2 a2)               \
 static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3)    \
 {                                                                      \
        rettype ret;                                                    \
-       current_config = c ? c->lxc_conf : NULL;                        \
+       bool reset_config = false;                                      \
+                                                                       \
+       if (!current_config && c && c->lxc_conf) {                      \
+               current_config = c->lxc_conf;                           \
+               reset_config = true;                                    \
+       }                                                               \
+                                                                       \
        ret = do_##fnname(c, a1, a2, a3);                               \
-       current_config = NULL;                                          \
+       if (reset_config)                                               \
+               current_config = NULL;                                  \
+                                                                       \
        return ret;                                                     \
 }
 
@@ -617,10 +649,64 @@ static bool am_single_threaded(void)
        return count == 1;
 }
 
-/*
- * 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 void push_arg(char ***argp, char *arg, int *nargs)
+{
+       char **argv;
+       char *copy;
+
+       do {
+               copy = strdup(arg);
+       } while (!copy);
+       do {
+               argv = realloc(*argp, (*nargs + 2) * sizeof(char *));
+       } while (!argv);
+       *argp = argv;
+       argv[*nargs] = copy;
+       (*nargs)++;
+       argv[*nargs] = NULL;
+}
+
+static char **split_init_cmd(const char *incmd)
+{
+       size_t len;
+       int nargs = 0;
+       char *copy, *p, *saveptr;
+       char **argv;
+
+       if (!incmd)
+               return NULL;
+
+       len = strlen(incmd) + 1;
+       copy = alloca(len);
+       strncpy(copy, incmd, len);
+       copy[len-1] = '\0';
+
+       do {
+               argv = malloc(sizeof(char *));
+       } while (!argv);
+       argv[0] = NULL;
+       for (p = strtok_r(copy, " ", &saveptr); p != NULL;
+                       p = strtok_r(NULL, " ", &saveptr))
+               push_arg(&argv, p, &nargs);
+
+       if (nargs == 0) {
+               free(argv);
+               return NULL;
+       }
+       return argv;
+}
+
+static void free_init_cmd(char **argv)
+{
+       int i = 0;
+
+       if (!argv)
+               return;
+       while (argv[i])
+               free(argv[i++]);
+       free(argv);
+}
+
 static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
 {
        int ret;
@@ -631,7 +717,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                "/sbin/init",
                NULL,
        };
-       char *init_cmd[2];
+       char **init_cmd = NULL;
 
        /* container exists */
        if (!c)
@@ -672,15 +758,14 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                return ret == 0 ? true : false;
        }
 
-       if (!argv) {
-               if (conf->init_cmd) {
-                       init_cmd[0] = conf->init_cmd;
-                       init_cmd[1] = NULL;
-                       argv = init_cmd;
-               }
-               else
-                       argv = default_args;
-       }
+       /* if no argv was passed in, use lxc.init_cmd if provided in
+        * configuration */
+       if (!argv)
+               argv = init_cmd = split_init_cmd(conf->init_cmd);
+
+       /* ... and otherwise use default_args */
+       if (!argv)
+               argv = default_args;
 
        /*
        * say, I'm not sure - what locks do we want here?  Any?
@@ -766,6 +851,18 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 
        conf->reboot = 0;
 
+       /* Unshare the mount namespace if requested */
+       if (conf->monitor_unshare) {
+               if (unshare(CLONE_NEWNS)) {
+                       SYSERROR("failed to unshare mount namespace");
+                       return false;
+               }
+               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+                       SYSERROR("Failed to make / rslave at startup");
+                       return false;
+               }
+       }
+
 reboot:
        if (lxc_check_inherited(conf, daemonize, -1)) {
                ERROR("Inherited fds found");
@@ -789,6 +886,8 @@ out:
                c->pidfile = NULL;
        }
 
+       free_init_cmd(init_cmd);
+
        if (daemonize)
                exit (ret == 0 ? true : false);
        else
@@ -938,6 +1037,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
        }
 
        do_lxcapi_set_config_item(c, "lxc.rootfs", bdev->src);
+       do_lxcapi_set_config_item(c, "lxc.rootfs.backend", bdev->type);
 
        /* if we are not root, chown the rootfs dir to root in the
         * target uidmap */
@@ -977,7 +1077,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
        }
 
        if (pid == 0) { // child
-               char *patharg, *namearg, *rootfsarg, *src;
+               char *patharg, *namearg, *rootfsarg;
                struct bdev *bdev = NULL;
                int i;
                int ret, len, nargs = 0;
@@ -988,18 +1088,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                        exit(1);
                }
 
-               src = c->lxc_conf->rootfs.path;
-               /*
-                * for an overlay create, what the user wants is the template to fill
-                * in what will become the readonly lower layer.  So don't mount for
-                * the template
-                */
-               if (strncmp(src, "overlayfs:", 10) == 0)
-                       src = overlay_getlower(src+10);
-               if (strncmp(src, "aufs:", 5) == 0)
-                       src = overlay_getlower(src+5);
-
-               bdev = bdev_init(c->lxc_conf, src, c->lxc_conf->rootfs.mount, NULL);
+               bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
                if (!bdev) {
                        ERROR("Error opening rootfs");
                        exit(1);
@@ -1276,6 +1365,9 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[])
        fprintf(f, "\n");
 #endif
        fprintf(f, "# For additional config options, please look at lxc.container.conf(5)\n");
+       fprintf(f, "\n# Uncomment the following line to support nesting containers:\n");
+       fprintf(f, "#lxc.include = " LXCTEMPLATECONFIG "/nesting.conf\n");
+       fprintf(f, "# (Be aware this has security implications)\n\n");
        if (fwrite(contents, 1, flen, f) != flen) {
                SYSERROR("Writing original contents");
                free(contents);
@@ -1479,6 +1571,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 static bool do_lxcapi_reboot(struct lxc_container *c)
 {
        pid_t pid;
+       int rebootsignal = SIGINT;
 
        if (!c)
                return false;
@@ -1487,7 +1580,9 @@ static bool do_lxcapi_reboot(struct lxc_container *c)
        pid = do_lxcapi_init_pid(c);
        if (pid <= 0)
                return false;
-       if (kill(pid, SIGINT) < 0)
+       if (c->lxc_conf && c->lxc_conf->rebootsignal)
+               rebootsignal = c->lxc_conf->rebootsignal;
+       if (kill(pid, rebootsignal) < 0)
                return false;
        return true;
 
@@ -1978,47 +2073,122 @@ out:
 
 WRAP_API_1(bool, lxcapi_save_config, const char *)
 
-static bool mod_rdep(struct lxc_container *c, bool inc)
+
+static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc)
 {
+       FILE *f1;
+       struct stat fbuf;
+       void *buf = NULL;
+       char *del = NULL;
        char path[MAXPATHLEN];
-       int ret, v = 0;
-       FILE *f;
+       char newpath[MAXPATHLEN];
+       int fd, ret, n = 0, v = 0;
        bool bret = false;
+       size_t len = 0, bytes = 0;
 
-       if (container_disk_lock(c))
+       if (container_disk_lock(c0))
                return false;
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
-                       c->name);
+
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
        if (ret < 0 || ret > MAXPATHLEN)
                goto out;
-       f = fopen(path, "r");
-       if (f) {
-               ret = fscanf(f, "%d", &v);
-               fclose(f);
-               if (ret != 1) {
-                       ERROR("Corrupted file %s", path);
-                       goto out;
-               }
-       }
-       v += inc ? 1 : -1;
-       f = fopen(path, "w");
-       if (!f)
-               goto out;
-       if (fprintf(f, "%d\n", v) < 0) {
-               ERROR("Error writing new snapshots value");
-               fclose(f);
+       ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
+       if (ret < 0 || ret > MAXPATHLEN)
                goto out;
+
+       /* If we find an lxc-snapshot file using the old format only listing the
+        * number of snapshots we will keep using it. */
+       f1 = fopen(path, "r");
+       if (f1) {
+               n = fscanf(f1, "%d", &v);
+               fclose(f1);
+               if (n == 1 && v == 0) {
+                       remove(path);
+                       n = 0;
+               }
        }
-       ret = fclose(f);
-       if (ret != 0) {
-               SYSERROR("Error writing to or closing snapshots file");
-               goto out;
+       if (n == 1) {
+               v += inc ? 1 : -1;
+               f1 = fopen(path, "w");
+               if (!f1)
+                       goto out;
+               if (fprintf(f1, "%d\n", v) < 0) {
+                       ERROR("Error writing new snapshots value");
+                       fclose(f1);
+                       goto out;
+               }
+               ret = fclose(f1);
+               if (ret != 0) {
+                       SYSERROR("Error writing to or closing snapshots file");
+                       goto out;
+               }
+       } else {
+               /* Here we know that we have or can use an lxc-snapshot file
+                * using the new format. */
+               if (inc) {
+                       f1 = fopen(path, "a");
+                       if (!f1)
+                               goto out;
+
+                       if (fprintf(f1, "%s", newpath) < 0) {
+                               ERROR("Error writing new snapshots entry");
+                               ret = fclose(f1);
+                               if (ret != 0)
+                                       SYSERROR("Error writing to or closing snapshots file");
+                               goto out;
+                       }
+
+                       ret = fclose(f1);
+                       if (ret != 0) {
+                               SYSERROR("Error writing to or closing snapshots file");
+                               goto out;
+                       }
+               } else if (!inc) {
+                       if ((fd = open(path, O_RDWR | O_CLOEXEC)) < 0)
+                               goto out;
+
+                       if (fstat(fd, &fbuf) < 0) {
+                               close(fd);
+                               goto out;
+                       }
+
+                       if (fbuf.st_size != 0) {
+
+                               buf = lxc_strmmap(NULL, fbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+                               if (buf == MAP_FAILED) {
+                                       SYSERROR("Failed to create mapping %s", path);
+                                       close(fd);
+                                       goto out;
+                               }
+
+                               len = strlen(newpath);
+                               while ((del = strstr((char *)buf, newpath))) {
+                                       memmove(del, del + len, strlen(del) - len + 1);
+                                       bytes += len;
+                               }
+
+                               lxc_strmunmap(buf, fbuf.st_size);
+                               if (ftruncate(fd, fbuf.st_size - bytes) < 0) {
+                                       SYSERROR("Failed to truncate file %s", path);
+                                       close(fd);
+                                       goto out;
+                               }
+                       }
+                       close(fd);
+               }
+
+               /* If the lxc-snapshot file is empty, remove it. */
+               if (stat(path, &fbuf) < 0)
+                       goto out;
+               if (!fbuf.st_size) {
+                       remove(path);
+               }
        }
 
        bret = true;
 
 out:
-       container_disk_unlock(c);
+       container_disk_unlock(c0);
        return bret;
 }
 
@@ -2031,7 +2201,7 @@ static void strip_newline(char *p)
                p[len-1] = '\0';
 }
 
-static void mod_all_rdeps(struct lxc_container *c, bool inc)
+void mod_all_rdeps(struct lxc_container *c, bool inc)
 {
        struct lxc_container *p;
        char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
@@ -2060,8 +2230,8 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc)
                                lxcpath, lxcname);
                        continue;
                }
-               if (!mod_rdep(p, inc))
-                       ERROR("Failed to increase numsnapshots for %s:%s",
+               if (!mod_rdep(p, c, inc))
+                       ERROR("Failed to update snapshots file for %s:%s",
                                lxcpath, lxcname);
                lxc_container_put(p);
        }
@@ -2073,22 +2243,30 @@ out:
 
 static bool has_fs_snapshots(struct lxc_container *c)
 {
+       FILE *f;
        char path[MAXPATHLEN];
        int ret, v;
-       FILE *f;
+       struct stat fbuf;
        bool bret = false;
 
        ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
                        c->name);
        if (ret < 0 || ret > MAXPATHLEN)
                goto out;
-       f = fopen(path, "r");
-       if (!f)
-               goto out;
-       ret = fscanf(f, "%d", &v);
-       fclose(f);
-       if (ret != 1)
+       /* If the file doesn't exist there are no snapshots. */
+       if (stat(path, &fbuf) < 0)
                goto out;
+       v = fbuf.st_size;
+       if (v != 0) {
+               f = fopen(path, "r");
+               if (!f)
+                       goto out;
+               ret = fscanf(f, "%d", &v);
+               fclose(f);
+               // TODO: Figure out what to do with the return value of fscanf.
+               if (ret != 1)
+                       INFO("Container uses new lxc-snapshots format %s", path);
+       }
        bret = v != 0;
 
 out:
@@ -2142,10 +2320,12 @@ static bool container_destroy(struct lxc_container *c)
 {
        bool bret = false;
        int ret = 0;
+       struct lxc_conf *conf;
 
        if (!c || !do_lxcapi_is_defined(c))
                return false;
 
+       conf = c->lxc_conf;
        if (container_disk_lock(c))
                return false;
 
@@ -2155,16 +2335,44 @@ static bool container_destroy(struct lxc_container *c)
                goto out;
        }
 
-       if (current_config && c->lxc_conf == current_config) {
+       if (conf && !lxc_list_empty(&conf->hooks[LXCHOOK_DESTROY])) {
+               /* Start of environment variable setup for hooks */
+               if (c->name && setenv("LXC_NAME", c->name, 1)) {
+                       SYSERROR("failed to set environment variable for container name");
+               }
+               if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) {
+                       SYSERROR("failed to set environment variable for config path");
+               }
+               if (conf->rootfs.mount && setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) {
+                       SYSERROR("failed to set environment variable for rootfs mount");
+               }
+               if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) {
+                       SYSERROR("failed to set environment variable for rootfs mount");
+               }
+               if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) {
+                       SYSERROR("failed to set environment variable for console path");
+               }
+               if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) {
+                       SYSERROR("failed to set environment variable for console log");
+               }
+               /* End of environment variable setup for hooks */
+
+               if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) {
+                       ERROR("Error executing clone hook for %s", c->name);
+                       goto out;
+               }
+       }
+
+       if (current_config && conf == current_config) {
                current_config = NULL;
-               if (c->lxc_conf->logfd != -1) {
-                       close(c->lxc_conf->logfd);
-                       c->lxc_conf->logfd = -1;
+               if (conf->logfd != -1) {
+                       close(conf->logfd);
+                       conf->logfd = -1;
                }
        }
 
-       if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount) {
-               if (!do_destroy_container(c->lxc_conf)) {
+       if (conf && conf->rootfs.path && conf->rootfs.mount) {
+               if (!do_destroy_container(conf)) {
                        ERROR("Error destroying rootfs for %s", c->name);
                        goto out;
                }
@@ -2177,7 +2385,7 @@ static bool container_destroy(struct lxc_container *c)
        char *path = alloca(strlen(p1) + strlen(c->name) + 2);
        sprintf(path, "%s/%s", p1, c->name);
        if (am_unpriv())
-               ret = userns_exec_1(c->lxc_conf, lxc_rmdir_onedev_wrapper, path);
+               ret = userns_exec_1(conf, lxc_rmdir_onedev_wrapper, path);
        else
                ret = lxc_rmdir_onedev(path, "snaps");
        if (ret < 0) {
@@ -2598,37 +2806,85 @@ static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
        return bret;
 }
 
+/*
+ * If the fs natively supports snapshot clones with no penalty,
+ * then default to those even if not requested.
+ * Currently we only do this for btrfs.
+ */
+bool should_default_to_snapshot(struct lxc_container *c0,
+                               struct lxc_container *c1)
+{
+       size_t l0 = strlen(c0->config_path) + strlen(c0->name) + 2;
+       size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2;
+       char *p0 = alloca(l0 + 1);
+       char *p1 = alloca(l1 + 1);
+
+       snprintf(p0, l0, "%s/%s", c0->config_path, c0->name);
+       snprintf(p1, l1, "%s/%s", c1->config_path, c1->name);
+
+       if (!is_btrfs_fs(p0) || !is_btrfs_fs(p1))
+               return false;
+
+       return btrfs_same_fs(p0, p1) == 0;
+}
+
 static int copy_storage(struct lxc_container *c0, struct lxc_container *c,
-               const char *newtype, int flags, const char *bdevdata, uint64_t newsize)
+                       const char *newtype, int flags, const char *bdevdata,
+                       uint64_t newsize)
 {
        struct bdev *bdev;
        int need_rdep;
 
-       bdev = bdev_copy(c0, c->name, c->config_path, newtype, flags,
-                       bdevdata, newsize, &need_rdep);
+       if (should_default_to_snapshot(c0, c))
+               flags |= LXC_CLONE_SNAPSHOT;
+
+       bdev = bdev_copy(c0, c->name, c->config_path, newtype, flags, bdevdata,
+                        newsize, &need_rdep);
        if (!bdev) {
-               ERROR("Error copying storage");
+               ERROR("Error copying storage.");
                return -1;
        }
+
+       /* Set new rootfs. */
        free(c->lxc_conf->rootfs.path);
        c->lxc_conf->rootfs.path = strdup(bdev->src);
+
+       /* Set new bdev type. */
+       free(c->lxc_conf->rootfs.bdev_type);
+       c->lxc_conf->rootfs.bdev_type = strdup(bdev->type);
        bdev_put(bdev);
+
        if (!c->lxc_conf->rootfs.path) {
-               ERROR("Out of memory while setting storage path");
+               ERROR("Out of memory while setting storage path.");
+               return -1;
+       }
+       if (!c->lxc_conf->rootfs.bdev_type) {
+               ERROR("Out of memory while setting rootfs backend.");
                return -1;
        }
-       // We will simply append a new lxc.rootfs entry to the unexpanded config
+
+       /* Append a new lxc.rootfs entry to the unexpanded config. */
        clear_unexp_config_line(c->lxc_conf, "lxc.rootfs", false);
-       if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs", c->lxc_conf->rootfs.path)) {
-               ERROR("Error saving new rootfs to cloned config");
+       if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs",
+                                        c->lxc_conf->rootfs.path)) {
+               ERROR("Error saving new rootfs to cloned config.");
                return -1;
        }
+
+       /* Append a new lxc.rootfs.backend entry to the unexpanded config. */
+       clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend", false);
+       if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend",
+                                        c->lxc_conf->rootfs.bdev_type)) {
+               ERROR("Error saving new rootfs backend to cloned config.");
+               return -1;
+       }
+
        if (flags & LXC_CLONE_SNAPSHOT)
                copy_rdepends(c, c0);
        if (need_rdep) {
                if (!add_rdepends(c, c0))
                        WARN("Error adding reverse dependency from %s to %s",
-                               c->name, c0->name);
+                            c->name, c0->name);
        }
 
        mod_all_rdeps(c, true);
@@ -2776,102 +3032,6 @@ static int create_file_dirname(char *path, struct lxc_conf *conf)
        return ret;
 }
 
-/* When we clone a container with overlay lxc.mount.entry entries we need to
-*  update absolute paths for upper- and workdir. This update is done in two
-*  locations: lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates
-*  are done independent of each other since lxc_conf->mountlist may container
-*  more mount entries (e.g. from other included files) than
-*  lxc_conf->unexpanded_config . */
-static int update_ovl_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
-                           const char *lxc_name, const char *newpath,
-                           const char *newname)
-{
-       char new_upper[MAXPATHLEN];
-       char new_work[MAXPATHLEN];
-       char old_upper[MAXPATHLEN];
-       char old_work[MAXPATHLEN];
-       char *cleanpath = NULL;
-       int i;
-       int fret = -1;
-       int ret = 0;
-       struct lxc_list *iterator;
-       const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
-
-       cleanpath = strdup(newpath);
-       if (!cleanpath)
-               goto err;
-
-       remove_trailing_slashes(cleanpath);
-
-       /* We have to update lxc_conf->unexpanded_config separately from
-       *  lxc_conf->mount_list. */
-       for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
-               if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
-                                                 lxc_name, newname,
-                                                 ovl_dirs[i]))
-                       goto err;
-       }
-
-       ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               goto err;
-
-       ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               goto err;
-
-       lxc_list_for_each(iterator, &lxc_conf->mount_list) {
-               char *mnt_entry = NULL;
-               char *new_mnt_entry = NULL;
-               char *tmp = NULL;
-               char *tmp_mnt_entry = NULL;
-               mnt_entry = iterator->elem;
-
-               if (strstr(mnt_entry, "overlay"))
-                       tmp = "upperdir";
-               else if (strstr(mnt_entry, "aufs"))
-                       tmp = "br";
-
-               if (!tmp)
-                       continue;
-
-               ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name);
-               if (ret < 0 || ret >= MAXPATHLEN)
-                       goto err;
-
-               ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname);
-               if (ret < 0 || ret >= MAXPATHLEN)
-                       goto err;
-
-               if (strstr(mnt_entry, old_upper)) {
-                       tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
-               }
-
-               if (strstr(mnt_entry, old_work)) {
-                       if (tmp_mnt_entry)
-                               new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry);
-                       else
-                               new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry);
-               }
-
-               if (new_mnt_entry) {
-                       free(iterator->elem);
-                       iterator->elem = strdup(new_mnt_entry);
-               } else if (tmp_mnt_entry) {
-                       free(iterator->elem);
-                       iterator->elem = strdup(tmp_mnt_entry);
-               }
-
-               free(new_mnt_entry);
-               free(tmp_mnt_entry);
-       }
-
-       fret = 0;
-err:
-       free(cleanpath);
-       return fret;
-}
-
 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,
@@ -2880,8 +3040,9 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        struct lxc_container *c2 = NULL;
        char newpath[MAXPATHLEN];
        int ret, storage_copied = 0;
-       char *origroot = NULL;
+       char *origroot = NULL, *saved_unexp_conf = NULL;
        struct clone_update_data data;
+       size_t saved_unexp_len;
        FILE *fout;
        pid_t pid;
 
@@ -2927,9 +3088,23 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                SYSERROR("open %s", newpath);
                goto out;
        }
+
+       saved_unexp_conf = c->lxc_conf->unexpanded_config;
+       saved_unexp_len = c->lxc_conf->unexpanded_len;
+       c->lxc_conf->unexpanded_config = strdup(saved_unexp_conf);
+       if (!c->lxc_conf->unexpanded_config) {
+               ERROR("Out of memory");
+               fclose(fout);
+               goto out;
+       }
+       clear_unexp_config_line(c->lxc_conf, "lxc.rootfs", false);
        write_config(fout, c->lxc_conf);
        fclose(fout);
        c->lxc_conf->rootfs.path = origroot;
+       free(c->lxc_conf->unexpanded_config);
+       c->lxc_conf->unexpanded_config = saved_unexp_conf;
+       saved_unexp_conf = NULL;
+       c->lxc_conf->unexpanded_len = saved_unexp_len;
 
        sprintf(newpath, "%s/%s/rootfs", lxcpath, newname);
        if (mkdir(newpath, 0755) < 0) {
@@ -2988,7 +3163,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        }
 
        // update absolute paths for overlay mount directories
-       if (update_ovl_paths(c2->lxc_conf, c->config_path, c->name, lxcpath, newname) < 0)
+       if (ovl_update_abs_paths(c2->lxc_conf, c->config_path, c->name, lxcpath, newname) < 0)
                goto out;
 
        // We've now successfully created c2's storage, so clear it out if we
@@ -3769,112 +3944,69 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, const char *ifna
 
 WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
 
-static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
+static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd,
+                            struct migrate_opts *opts, unsigned int size)
 {
-       pid_t pid;
-       int status;
-       char path[PATH_MAX];
-
-       if (!criu_ok(c))
-               return false;
-
-       if (mkdir(directory, 0700) < 0 && errno != EEXIST)
-               return false;
-
-       status = snprintf(path, sizeof(path), "%s/inventory.img", directory);
-       if (status < 0 || status >= sizeof(path))
-               return false;
+       int ret;
 
-       if (access(path, F_OK) == 0) {
-               ERROR("please use a fresh directory for the dump directory\n");
-               return false;
+       /* If the caller has a bigger (newer) struct migrate_opts, let's make
+        * sure that the stuff on the end is zero, i.e. that they didn't ask us
+        * to do anything special.
+        */
+       if (size > sizeof(*opts)) {
+               unsigned char *addr;
+               unsigned char *end;
+
+               addr = (void *)opts + sizeof(*opts);
+               end  = (void *)opts + size;
+               for (; addr < end; addr++) {
+                       if (*addr) {
+                               return -E2BIG;
+                       }
+               }
        }
 
-       pid = fork();
-       if (pid < 0)
-               return false;
-
-       if (pid == 0) {
-               struct criu_opts os;
+       switch (cmd) {
+       case MIGRATE_PRE_DUMP:
+               ret = !__criu_pre_dump(c, opts->directory, opts->verbose, opts->predump_dir, opts->pageserver_address, opts->pageserver_port);
+               break;
+       case MIGRATE_DUMP:
+               ret = !__criu_dump(c, opts->directory, opts->stop, opts->verbose, opts->predump_dir, opts->pageserver_address, opts->pageserver_port);
+               break;
+       case MIGRATE_RESTORE:
+               ret = !__criu_restore(c, opts->directory, opts->verbose);
+               break;
+       default:
+               ERROR("invalid migrate command %u", cmd);
+               ret = -EINVAL;
+       }
 
-               os.action = "dump";
-               os.directory = directory;
-               os.c = c;
-               os.stop = stop;
-               os.verbose = verbose;
+       return ret;
+}
 
-               /* exec_criu() returning is an error */
-               exec_criu(&os);
-               exit(1);
-       } else {
-               pid_t w = waitpid(pid, &status, 0);
-               if (w == -1) {
-                       SYSERROR("waitpid");
-                       return false;
-               }
+WRAP_API_3(int, lxcapi_migrate, unsigned int, struct migrate_opts *, unsigned int)
 
-               if (WIFEXITED(status)) {
-                       return !WEXITSTATUS(status);
-               }
+static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
+{
+       struct migrate_opts opts = {
+               .directory = directory,
+               .stop = stop,
+               .verbose = verbose,
+       };
 
-               return false;
-       }
+       return !do_lxcapi_migrate(c, MIGRATE_DUMP, &opts, sizeof(opts));
 }
 
 WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool)
 
 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;
+       struct migrate_opts opts = {
+               .directory = directory,
+               .verbose = verbose,
+       };
 
-err_wait:
-       if (wait_for_pid(pid))
-               ERROR("restore process died");
-       return false;
+       return !do_lxcapi_migrate(c, MIGRATE_RESTORE, &opts, sizeof(opts));
 }
 
 WRAP_API_2(bool, lxcapi_restore, char *, bool)
@@ -4020,6 +4152,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
        c->detach_interface = lxcapi_detach_interface;
        c->checkpoint = lxcapi_checkpoint;
        c->restore = lxcapi_restore;
+       c->migrate = lxcapi_migrate;
 
        return c;
 
@@ -4066,9 +4199,9 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
        while (!readdir_r(dir, &dirent, &direntp)) {
                if (!direntp)
                        break;
-               if (!strcmp(direntp->d_name, "."))
-                       continue;
-               if (!strcmp(direntp->d_name, ".."))
+
+               // Ignore '.', '..' and any hidden directory
+               if (!strncmp(direntp->d_name, ".", 1))
                        continue;
 
                if (!config_file_exists(lxcpath, direntp->d_name))
index d8b20ec..0e014bc 100644 (file)
@@ -49,8 +49,14 @@ struct lxc_snapshot;
 
 struct lxc_lock;
 
+struct migrate_opts;
+
 /*!
  * An LXC container.
+ *
+ * Note that changing the order of struct members is an API change, as callers
+ * will end up having the wrong offset when calling a function.  So when making
+ * changes, whenever possible stick to simply appending new members.
  */
 struct lxc_container {
        // private fields
@@ -216,25 +222,24 @@ struct lxc_container {
        bool (*stop)(struct lxc_container *c);
 
        /*!
-        * \brief Determine if the container wants to run disconnected
+        * \brief Change whether the container wants to run disconnected
         * from the terminal.
         *
         * \param c Container.
         * \param state Value for the daemonize bit (0 or 1).
         *
-        * \return \c true if container wants to be daemonised, else \c false.
+        * \return \c true on success, else \c false.
         */
        bool (*want_daemonize)(struct lxc_container *c, bool state);
 
        /*!
-        * \brief Determine whether container wishes all file descriptors
+        * \brief Change whether the container wishes all file descriptors
         *  to be closed on startup.
         *
         * \param c Container.
         * \param state Value for the close_all_fds bit (0 or 1).
         *
-        * \return \c true if container wants all file descriptors closed,
-        *  else \c false.
+        * \return \c true on success, else \c false.
         */
        bool (*want_close_all_fds)(struct lxc_container *c, bool state);
 
@@ -808,6 +813,16 @@ struct lxc_container {
        bool (*snapshot_destroy_all)(struct lxc_container *c);
 
        /* Post LXC-1.1 additions */
+       /*!
+        * \brief An API call to perform various migration operations
+        *
+        * \param cmd One of the MIGRATE_ contstants.
+        * \param opts A migrate_opts struct filled with relevant options.
+        * \param size The size of the migrate_opts struct, i.e. sizeof(struct migrate_opts).
+        *
+        * \return \c 0 on success, nonzero on failure.
+        */
+       int (*migrate)(struct lxc_container *c, unsigned int cmd, struct migrate_opts *opts, unsigned int size);
 };
 
 /*!
@@ -842,6 +857,33 @@ struct bdev_specs {
                char *thinpool; /*!< LVM thin pool to use, if any */
        } lvm;
        char *dir; /*!< Directory path */
+       struct {
+               char *rbdname; /*!< RBD image name */
+               char *rbdpool; /*!< Ceph pool name */
+       } rbd;
+};
+
+/*!
+ * \brief Commands for the migrate API call.
+ */
+enum {
+       MIGRATE_PRE_DUMP,
+       MIGRATE_DUMP,
+       MIGRATE_RESTORE,
+};
+
+/*!
+ * \brief Options for the migrate API call.
+ */
+struct migrate_opts {
+       /* new members should be added at the end */
+       char *directory;
+       bool verbose;
+
+       bool stop; /* stop the container after dump? */
+       char *predump_dir; /* relative to directory above */
+       char *pageserver_address; /* where should memory pages be send? */
+       char *pageserver_port;
 };
 
 /*!
index 28f17e6..027c765 100644 (file)
@@ -34,6 +34,9 @@
 #ifndef CLONE_NEWNS
 #  define CLONE_NEWNS             0x00020000
 #endif
+#ifndef CLONE_NEWCGROUP
+#  define CLONE_NEWCGROUP         0x02000000
+#endif
 #ifndef CLONE_NEWUTS
 #  define CLONE_NEWUTS            0x04000000
 #endif
index a6740f5..31c82bb 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
+#include <sys/inotify.h>
 #include <arpa/inet.h>
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -109,6 +110,8 @@ int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi)
+               goto out;
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = ifindex;
 
@@ -158,8 +161,10 @@ static char * is_wlan(const char *ifname)
        physlen = ftell(f);
        fseek(f, 0, SEEK_SET);
        physname = malloc(physlen+1);
-       if (!physname)
+       if (!physname) {
+               fclose(f);
                goto bad;
+       }
        memset(physname, 0, physlen+1);
        ret = fread(physname, 1, physlen, f);
        fclose(f);
@@ -216,7 +221,7 @@ lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, const char*
        if (fpid == 0) {
                char pidstr[30];
                sprintf(pidstr, "%d", pid);
-               if (execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, NULL))
+               if (execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, (char *)NULL))
                        exit(1);
                exit(0); // notreached
        }
@@ -274,6 +279,8 @@ int lxc_netdev_delete_by_index(int ifindex)
        nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi)
+               goto out;
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = ifindex;
 
@@ -324,6 +331,8 @@ int lxc_netdev_rename_by_index(int ifindex, const char *newname)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi)
+               goto out;
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = ifindex;
 
@@ -387,6 +396,10 @@ int netdev_set_flag(const char *name, int flag)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi) {
+               err = -ENOMEM;
+               goto out;
+       }
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = index;
        ifi->ifi_change |= IFF_UP;
@@ -437,6 +450,10 @@ int netdev_get_flag(const char* name, int *flag)
        nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi) {
+               err = -ENOMEM;
+               goto out;
+       }
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = index;
 
@@ -511,6 +528,8 @@ int netdev_get_mtu(int ifindex)
        nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi)
+               goto out;
        ifi->ifi_family = AF_UNSPEC;
 
        /* Send the request for addresses, which returns all addresses
@@ -622,6 +641,10 @@ int lxc_netdev_set_mtu(const char *name, int mtu)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi) {
+               err = -ENOMEM;
+               goto out;
+       }
        ifi->ifi_family = AF_UNSPEC;
        ifi->ifi_index = index;
 
@@ -681,6 +704,8 @@ int lxc_veth_create(const char *name1, const char *name2)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi)
+               goto out;
        ifi->ifi_family = AF_UNSPEC;
 
        err = -EINVAL;
@@ -700,8 +725,10 @@ int lxc_veth_create(const char *name1, const char *name2)
                goto out;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
-       if (!ifi)
+       if (!ifi) {
+               err = -ENOMEM;
                goto out;
+       }
 
        if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
                goto out;
@@ -764,6 +791,10 @@ int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi) {
+               err = -ENOMEM;
+               goto err1;
+       }
        ifi->ifi_family = AF_UNSPEC;
 
        nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
@@ -840,6 +871,10 @@ int lxc_macvlan_create(const char *master, const char *name, int mode)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+       if (!ifi) {
+               err = -ENOMEM;
+               goto out;
+       }
        ifi->ifi_family = AF_UNSPEC;
 
        nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
@@ -1021,11 +1056,13 @@ static int ip_addr_add(int family, int ifindex,
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR;
 
        ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
+       if (!ifa)
+               goto out;
        ifa->ifa_prefixlen = prefix;
        ifa->ifa_index = ifindex;
        ifa->ifa_family = family;
        ifa->ifa_scope = 0;
-       
+
        err = -EINVAL;
        if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
                goto out;
@@ -1142,6 +1179,8 @@ static int ip_addr_get(int family, int ifindex, void **res)
        nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR;
 
        ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
+       if (!ifa)
+               goto out;
        ifa->ifa_family = family;
 
        /* Send the request for addresses, which returns all addresses
@@ -1256,6 +1295,8 @@ static int ip_gateway_add(int family, int ifindex, void *gw)
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
 
        rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
+       if (!rt)
+               goto out;
        rt->rtm_family = family;
        rt->rtm_table = RT_TABLE_MAIN;
        rt->rtm_scope = RT_SCOPE_UNIVERSE;
@@ -1298,35 +1339,37 @@ static int ip_route_dest_add(int family, int ifindex, void *dest)
        struct rtmsg *rt;
        int addrlen;
        int err;
-       
+
        addrlen = family == AF_INET ? sizeof(struct in_addr) :
                sizeof(struct in6_addr);
-       
+
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
                return err;
-       
+
        err = -ENOMEM;
        nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
        if (!nlmsg)
                goto out;
-       
+
        answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
        if (!answer)
                goto out;
-       
+
        nlmsg->nlmsghdr->nlmsg_flags =
                NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
 
        rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
+       if (!rt)
+               goto out;
        rt->rtm_family = family;
        rt->rtm_table = RT_TABLE_MAIN;
        rt->rtm_scope = RT_SCOPE_LINK;
        rt->rtm_protocol = RTPROT_BOOT;
        rt->rtm_type = RTN_UNICAST;
        rt->rtm_dst_len = addrlen*8;
-       
+
        err = -EINVAL;
        if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
                goto out;
@@ -1361,10 +1404,25 @@ static bool is_ovs_bridge(const char *bridge)
        return false;
 }
 
-static int attach_to_ovs_bridge(const char *bridge, const char *nic)
+/*
+ * Called from a background thread - when nic goes away, remove
+ * it from the bridge
+ */
+static void ovs_cleanup_nic(const char *lxcpath, const char *name, const char *bridge, const char *nic)
+{
+       if (lxc_check_inherited(NULL, true, -1) < 0)
+               return;
+       if (lxc_wait(name, "STOPPED", -1, lxcpath) < 0)
+               return;
+       execlp("ovs-vsctl", "ovs-vsctl", "del-port", bridge, nic, (char *)NULL);
+       exit(1); /* not reached */
+}
+
+static int attach_to_ovs_bridge(const char *lxcpath, const char *name, const char *bridge, const char *nic)
 {
        pid_t pid;
        char *cmd;
+       int ret;
 
        cmd = on_path("ovs-vsctl", NULL);
        if (!cmd)
@@ -1374,10 +1432,20 @@ static int attach_to_ovs_bridge(const char *bridge, const char *nic)
        pid = fork();
        if (pid < 0)
                return -1;
-       if (pid > 0)
-               return wait_for_pid(pid);
+       if (pid > 0) {
+               ret = wait_for_pid(pid);
+               if (ret < 0)
+                       return ret;
+               pid = fork();
+               if (pid < 0)
+                       return -1;  // how to properly recover?
+               if (pid > 0)
+                       return 0;
+               ovs_cleanup_nic(lxcpath, name, bridge, nic);
+               exit(0);
+       }
 
-       if (execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, NULL))
+       if (execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, (char *)NULL))
                exit(1);
        // not reached
        exit(1);
@@ -1387,7 +1455,7 @@ static int attach_to_ovs_bridge(const char *bridge, const char *nic)
  * There is a lxc_bridge_attach, but no need of a bridge detach
  * as automatically done by kernel when a netdev is deleted.
  */
-int lxc_bridge_attach(const char *bridge, const char *ifname)
+int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, const char *ifname)
 {
        int fd, index, err;
        struct ifreq ifr;
@@ -1400,7 +1468,7 @@ int lxc_bridge_attach(const char *bridge, const char *ifname)
                return -EINVAL;
 
        if (is_ovs_bridge(bridge))
-               return attach_to_ovs_bridge(bridge, ifname);
+               return attach_to_ovs_bridge(lxcpath, name, bridge, ifname);
 
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd < 0)
index cd42c8f..aa19dae 100644 (file)
@@ -109,7 +109,7 @@ extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
 /*
  * Attach an interface to the bridge
  */
-extern int lxc_bridge_attach(const char *bridge, const char *ifname);
+extern int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, const char *ifname);
 
 /*
  * Create default gateway
index cfa5cdf..19a3a6c 100644 (file)
@@ -265,6 +265,7 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
        socklen_t socklen;
        int sndbuf = 32768;
        int rcvbuf = 32768;
+       int err;
 
        memset(handler, 0, sizeof(*handler));
 
@@ -274,11 +275,11 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
 
        if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
                       &sndbuf, sizeof(sndbuf)) < 0)
-               return -errno;
+               goto err_with_errno;
 
        if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
                       &rcvbuf,sizeof(rcvbuf)) < 0)
-               return -errno;
+               goto err_with_errno;
 
        memset(&handler->local, 0, sizeof(handler->local));
        handler->local.nl_family = AF_NETLINK;
@@ -286,22 +287,31 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
 
        if (bind(handler->fd, (struct sockaddr*)&handler->local,
                 sizeof(handler->local)) < 0)
-               return -errno;
+               goto err_with_errno;
 
        socklen = sizeof(handler->local);
        if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
                        &socklen) < 0)
-               return -errno;
+               goto err_with_errno;
 
-       if (socklen != sizeof(handler->local))
-               return -EINVAL;
+       if (socklen != sizeof(handler->local)) {
+               err = -EINVAL;
+               goto errclose;
+       }
 
-       if (handler->local.nl_family != AF_NETLINK)
-               return -EINVAL;
+       if (handler->local.nl_family != AF_NETLINK) {
+               err = -EINVAL;
+               goto errclose;
+       }
 
        handler->seq = time(NULL);
 
        return 0;
+err_with_errno:
+       err = -errno;
+errclose:
+       close(handler->fd);
+       return err;
 }
 
 extern int netlink_close(struct nl_handler *handler)
index 0208646..451e315 100644 (file)
@@ -300,6 +300,24 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
                                default_policy_action);
                if (!compat_ctx)
                        goto bad;
+#ifdef SCMP_ARCH_PPC
+       } else if (native_arch == lxc_seccomp_arch_ppc64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch = SCMP_ARCH_PPC;
+               compat_ctx = get_new_ctx(lxc_seccomp_arch_ppc,
+                               default_policy_action);
+               if (!compat_ctx)
+                       goto bad;
+#endif
+#ifdef SCMP_ARCH_ARM
+       } else if (native_arch == lxc_seccomp_arch_arm64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch = SCMP_ARCH_ARM;
+               compat_ctx = get_new_ctx(lxc_seccomp_arch_arm,
+                               default_policy_action);
+               if (!compat_ctx)
+                       goto bad;
+#endif
        }
 
        if (default_policy_action != SCMP_ACT_KILL) {
@@ -327,7 +345,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
                        if (strcmp(line, "[x86]") == 0 ||
                                        strcmp(line, "[X86]") == 0) {
                                if (native_arch != lxc_seccomp_arch_i386 &&
-                                       native_arch != lxc_seccomp_arch_amd64) {
+                                               native_arch != lxc_seccomp_arch_amd64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
@@ -346,7 +364,8 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 #ifdef SCMP_ARCH_ARM
                        else if (strcmp(line, "[arm]") == 0 ||
                                        strcmp(line, "[ARM]") == 0) {
-                               if (native_arch != lxc_seccomp_arch_arm) {
+                               if (native_arch != lxc_seccomp_arch_arm &&
+                                               native_arch != lxc_seccomp_arch_arm64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
@@ -386,7 +405,8 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 #ifdef SCMP_ARCH_PPC
                        else if (strcmp(line, "[ppc]") == 0 ||
                                        strcmp(line, "[PPC]") == 0) {
-                               if (native_arch != lxc_seccomp_arch_ppc) {
+                               if (native_arch != lxc_seccomp_arch_ppc &&
+                                               native_arch != lxc_seccomp_arch_ppc64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
@@ -435,7 +455,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
        if (compat_ctx) {
                INFO("Merging in the compat seccomp ctx into the main one");
                if (seccomp_merge(conf->seccomp_ctx, compat_ctx) != 0) {
-                       ERROR("Error merging i386 seccomp contexts");
+                       ERROR("Error merging compat seccomp contexts");
                        goto bad;
                }
        }
@@ -538,6 +558,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
 {
        FILE *f;
        int ret;
+       int check_seccomp_attr_set;
 
        if (!conf->seccomp)
                return 0;
@@ -558,11 +579,12 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
 
        /* turn of no-new-privs.  We don't want it in lxc, and it breaks
         * with apparmor */
-       if (seccomp_attr_set(
 #if HAVE_SCMP_FILTER_CTX
-                       conf->seccomp_ctx,
+  check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
+#else
+  check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
 #endif
-                       SCMP_FLTATR_CTL_NNP, 0)) {
+       if (check_seccomp_attr_set) {
                ERROR("failed to turn off n-new-privs");
                return -1;
        }
index fa905e2..5be0077 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define _GNU_SOURCE
 #include "config.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
+#include <alloca.h>
 #include <dirent.h>
 #include <errno.h>
-#include <unistd.h>
-#include <signal.h>
 #include <fcntl.h>
 #include <grp.h>
 #include <poll.h>
-#include <sys/param.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 #include <sys/file.h>
 #include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include <sys/param.h>
 #include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
-#include <sys/wait.h>
 #include <sys/un.h>
-#include <sys/syscall.h>
+#include <sys/wait.h>
 
 #if HAVE_SYS_CAPABILITY_H
 #include <sys/capability.h>
 #define PR_CAPBSET_DROP 24
 #endif
 
-#include "start.h"
-#include "conf.h"
-#include "log.h"
+#include "af_unix.h"
+#include "caps.h"
 #include "cgroup.h"
+#include "commands.h"
+#include "conf.h"
+#include "console.h"
 #include "error.h"
-#include "af_unix.h"
-#include "mainloop.h"
-#include "utils.h"
+#include "log.h"
+#include "lxclock.h"
+#include "lxcseccomp.h"
 #include "lxcutmp.h"
+#include "mainloop.h"
 #include "monitor.h"
-#include "commands.h"
-#include "console.h"
-#include "sync.h"
 #include "namespace.h"
-#include "lxcseccomp.h"
-#include "caps.h"
-#include "bdev.h"
+#include "start.h"
+#include "sync.h"
+#include "utils.h"
+#include "bdev/bdev.h"
 #include "lsm/lsm.h"
 
 lxc_log_define(lxc_start, lxc);
@@ -83,17 +85,25 @@ const struct ns_info ns_info[LXC_NS_MAX] = {
        [LXC_NS_NET] = {"net", CLONE_NEWNET}
 };
 
+extern void mod_all_rdeps(struct lxc_container *c, bool inc);
+static bool do_destroy_container(struct lxc_conf *conf);
+static int lxc_rmdir_onedev_wrapper(void *data);
+static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
+                                           const char *name);
+
 static void print_top_failing_dir(const char *path)
 {
        size_t len = strlen(path);
-       char *copy = alloca(len+1), *p, *e, saved;
+       char *copy = alloca(len + 1), *p, *e, saved;
        strcpy(copy, path);
 
        p = copy;
        e = copy + len;
        while (p < e) {
-               while (p < e && *p == '/') p++;
-               while (p < e && *p != '/') p++;
+               while (p < e && *p == '/')
+                       p++;
+               while (p < e && *p != '/')
+                       p++;
                saved = *p;
                *p = '\0';
                if (access(copy, X_OK)) {
@@ -117,8 +127,16 @@ static void close_ns(int ns_fd[LXC_NS_MAX]) {
        }
 }
 
-static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) {
-       int i, saved_errno;
+/*
+ * preserve_ns: open /proc/@pid/ns/@ns for each namespace specified
+ * in clone_flags.
+ * Return true on success, false on failure.  On failure, leave an error
+ * message in *errmsg, which caller must free.
+ */
+static bool preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid,
+                       char **errmsg)
+{
+       int i, ret;
        char path[MAXPATHLEN];
 
        for (i = 0; i < LXC_NS_MAX; i++)
@@ -126,8 +144,9 @@ static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) {
 
        snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
        if (access(path, X_OK)) {
-               WARN("Kernel does not support attach; preserve_ns ignored");
-               return 0;
+               if (asprintf(errmsg, "Kernel does not support setns.") == -1)
+                       *errmsg = NULL;
+               return false;
        }
 
        for (i = 0; i < LXC_NS_MAX; i++) {
@@ -140,14 +159,20 @@ static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) {
                        goto error;
        }
 
-       return 0;
+       return true;
 
 error:
-       saved_errno = errno;
+       if (errno == ENOENT) {
+               ret = asprintf(errmsg, "Kernel does not support setns for %s",
+                       ns_info[i].proc_name);
+       } else {
+               ret = asprintf(errmsg, "Failed to open %s: %s",
+                       path, strerror(errno));
+       }
+       if (ret == -1)
+               *errmsg = NULL;
        close_ns(ns_fd);
-       errno = saved_errno;
-       SYSERROR("failed to open '%s'", path);
-       return -1;
+       return false;
 }
 
 static int attach_ns(const int ns_fd[LXC_NS_MAX]) {
@@ -267,7 +292,7 @@ static int setup_signal_fd(sigset_t *oldmask)
 }
 
 static int signal_handler(int fd, uint32_t events, void *data,
-                          struct lxc_epoll_descr *descr)
+                         struct lxc_epoll_descr *descr)
 {
        struct signalfd_siginfo siginfo;
        siginfo_t info;
@@ -430,6 +455,9 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
        if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) {
                SYSERROR("failed to set environment variable for console log");
        }
+       if (setenv("LXC_CGNS_AWARE", "1", 1)) {
+               SYSERROR("failed to set LXC_CGNS_AWARE environment variable");
+       }
        /* End of environment variable setup for hooks */
 
        if (run_lxc_hooks(name, "pre-start", conf, handler->lxcpath, NULL)) {
@@ -479,7 +507,10 @@ out_free:
 
 void lxc_fini(const char *name, struct lxc_handler *handler)
 {
-       int i;
+       int i, rc;
+       pid_t self = getpid();
+       char *namespaces[LXC_NS_MAX+1];
+       size_t namespace_count = 0;
 
        /* The STOPPING state is there for future cleanup code
         * which can take awhile
@@ -488,14 +519,45 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
 
        for (i = 0; i < LXC_NS_MAX; i++) {
                if (handler->nsfd[i] != -1) {
+                       rc = asprintf(&namespaces[namespace_count], "%s:/proc/%d/fd/%d",
+                                     ns_info[i].proc_name, self, handler->nsfd[i]);
+                       if (rc == -1) {
+                               SYSERROR("failed to allocate memory");
+                               break;
+                       }
+                       ++namespace_count;
+               }
+       }
+       namespaces[namespace_count] = NULL;
+
+       if (handler->conf->reboot && setenv("LXC_TARGET", "reboot", 1)) {
+               SYSERROR("failed to set environment variable for stop target");
+       }
+       if (!handler->conf->reboot && setenv("LXC_TARGET", "stop", 1)) {
+               SYSERROR("failed to set environment variable for stop target");
+       }
+
+       if (run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, namespaces))
+               ERROR("failed to run stop hooks for container '%s'.", name);
+
+       while (namespace_count--)
+               free(namespaces[namespace_count]);
+       for (i = 0; i < LXC_NS_MAX; i++) {
+               if (handler->nsfd[i] != -1) {
                        close(handler->nsfd[i]);
                        handler->nsfd[i] = -1;
                }
        }
        lxc_set_state(name, handler, STOPPED);
 
-       if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL))
+       if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) {
                ERROR("failed to run post-stop hooks for container '%s'.", name);
+               if (handler->conf->reboot) {
+                       WARN("Container will be stopped instead of rebooted.");
+                       handler->conf->reboot = 0;
+                       setenv("LXC_TARGET", "stop", 1);
+               }
+       }
 
        /* reset mask set by setup_signal_fd */
        if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
@@ -510,6 +572,10 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
                close(handler->ttysock[0]);
                close(handler->ttysock[1]);
        }
+
+       if (handler->conf->ephemeral == 1 && handler->conf->reboot != 1)
+               lxc_destroy_container_on_signal(handler, name);
+
        cgroup_destroy(handler);
        free(handler);
 }
@@ -644,6 +710,8 @@ static int do_start(void *data)
 {
        struct lxc_list *iterator;
        struct lxc_handler *handler = data;
+       int devnull_fd = -1, ret;
+       char path[PATH_MAX];
 
        if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
                SYSERROR("failed to set sigprocmask");
@@ -679,15 +747,25 @@ static int do_start(void *data)
 
        /*
         * if we are in a new user namespace, become root there to have
-        * privilege over our namespace
+        * privilege over our namespace. When using lxc-execute we default to root,
+        * but this can be overriden using the lxc.init_uid and lxc.init_gid
+        * configuration options.
         */
        if (!lxc_list_empty(&handler->conf->id_map)) {
-               NOTICE("switching to gid/uid 0 in new user namespace");
-               if (setgid(0)) {
+               gid_t new_gid = 0;
+               if (handler->conf->is_execute && handler->conf->init_gid)
+                       new_gid = handler->conf->init_gid;
+
+               uid_t new_uid = 0;
+               if (handler->conf->is_execute && handler->conf->init_uid)
+                       new_uid = handler->conf->init_uid;
+
+               NOTICE("switching to gid/uid %d/%d in new user namespace", new_gid, new_uid);
+               if (setgid(new_gid)) {
                        SYSERROR("setgid");
                        goto out_warn_father;
                }
-               if (setuid(0)) {
+               if (setuid(new_uid)) {
                        SYSERROR("setuid");
                        goto out_warn_father;
                }
@@ -712,6 +790,30 @@ static int do_start(void *data)
        }
        #endif
 
+       ret = snprintf(path, sizeof(path), "%s/dev/null", handler->conf->rootfs.mount);
+       if (ret < 0 || ret >= sizeof(path)) {
+               SYSERROR("sprintf'd too many chars");
+               goto out_warn_father;
+       }
+
+       /* In order to checkpoint restore, we need to have everything in the
+        * same mount namespace. However, some containers may not have a
+        * reasonable /dev (in particular, they may not have /dev/null), so we
+        * can't set init's std fds to /dev/null by opening it from inside the
+        * container.
+        *
+        * If that's the case, fall back to using the host's /dev/null. This
+        * means that migration won't work, but at least we won't spew output
+        * where it isn't wanted.
+        */
+       if (handler->backgrounded && !handler->conf->autodev && access(path, F_OK) < 0) {
+               devnull_fd = open_devnull();
+
+               if (devnull_fd < 0)
+                       goto out_warn_father;
+               WARN("using host's /dev/null for container init's std fds, migraiton won't work");
+       }
+
        /* Setup the container, ip, names, utsname, ... */
        if (lxc_setup(handler)) {
                ERROR("failed to setup the container");
@@ -720,7 +822,7 @@ static int do_start(void *data)
 
        /* ask father to setup cgroups and wait for him to finish */
        if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP))
-               return -1;
+               goto out_error;
 
        /* Set the label to change to when we exec(2) the container's init */
        if (lsm_process_label_set(NULL, handler->conf, 1, 1) < 0)
@@ -732,7 +834,7 @@ static int do_start(void *data)
         * setup on its console ie. the pty allocated in lxc_console_create()
         * so make sure that that pty is stdin,stdout,stderr.
         */
-       if (lxc_console_set_stdfds(handler) < 0)
+       if (lxc_console_set_stdfds(handler->conf->console.slave) < 0)
                goto out_warn_father;
 
        /* If we mounted a temporary proc, then unmount it now */
@@ -777,23 +879,51 @@ static int do_start(void *data)
 
        close(handler->sigfd);
 
-       if (handler->backgrounded && null_stdfds() < 0)
+       if (devnull_fd < 0) {
+               devnull_fd = open_devnull();
+
+               if (devnull_fd < 0)
+                       goto out_warn_father;
+       }
+
+       if (handler->backgrounded && set_stdfds(devnull_fd))
                goto out_warn_father;
 
+       if (devnull_fd >= 0) {
+               close(devnull_fd);
+               devnull_fd = -1;
+       }
+
+       if (cgns_supported() && unshare(CLONE_NEWCGROUP) != 0) {
+               SYSERROR("Failed to unshare cgroup namespace");
+               goto out_warn_father;
+       }
+
+       setsid();
+
        /* after this call, we are in error because this
         * ops should not return as it execs */
        handler->ops->start(handler, handler->data);
 
 out_warn_father:
-       /* we want the parent to know something went wrong, so any
-        * value other than what it expects is ok. */
-       lxc_sync_wake_parent(handler, LXC_SYNC_POST_CONFIGURE);
+       /* we want the parent to know something went wrong, so we return a special
+        * error code. */
+       lxc_sync_wake_parent(handler, LXC_SYNC_ERROR);
+
+out_error:
+       if (devnull_fd >= 0)
+               close(devnull_fd);
+
        return -1;
 }
 
 static int save_phys_nics(struct lxc_conf *conf)
 {
        struct lxc_list *iterator;
+       int am_root = (getuid() == 0);
+
+       if (!am_root)
+               return 0;
 
        lxc_list_for_each(iterator, &conf->network) {
                struct lxc_netdev *netdev = iterator->elem;
@@ -894,6 +1024,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 {
        int failed_before_rename = 0;
        const char *name = handler->name;
+       char *errmsg = NULL;
        bool cgroups_connected = false;
        int saved_ns_fd[LXC_NS_MAX];
        int preserve_mask = 0, i;
@@ -968,8 +1099,12 @@ static int lxc_spawn(struct lxc_handler *handler)
                        INFO("failed to pin the container's rootfs");
        }
 
-       if (preserve_ns(saved_ns_fd, preserve_mask, getpid()) < 0)
+       if (!preserve_ns(saved_ns_fd, preserve_mask, getpid(), &errmsg)) {
+               SYSERROR("Failed to preserve requested namespaces: %s",
+                       errmsg ? errmsg : "(Out of memory)");
+               free(errmsg);
                goto out_delete_net;
+       }
        if (attach_ns(handler->conf->inherit_ns_fd) < 0)
                goto out_delete_net;
 
@@ -989,9 +1124,10 @@ static int lxc_spawn(struct lxc_handler *handler)
                goto out_delete_net;
        }
 
-       if (preserve_ns(handler->nsfd, handler->clone_flags, handler->pid) < 0) {
-           ERROR("failed to store namespace references");
-           goto out_delete_net;
+       if (!preserve_ns(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid, &errmsg)) {
+               INFO("Failed to store namespace references for stop hook: %s",
+                       errmsg ? errmsg : "(Out of memory)");
+               free(errmsg);
        }
 
        if (attach_ns(saved_ns_fd))
@@ -1022,7 +1158,8 @@ static int lxc_spawn(struct lxc_handler *handler)
 
        /* Create the network configuration */
        if (handler->clone_flags & CLONE_NEWNET) {
-               if (lxc_assign_network(&handler->conf->network, handler->pid)) {
+               if (lxc_assign_network(handler->lxcpath, handler->name,
+                                       &handler->conf->network, handler->pid)) {
                        ERROR("failed to create the configured network");
                        goto out_delete_net;
                }
@@ -1301,3 +1438,65 @@ int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf,
        conf->need_utmp_watch = 1;
        return __lxc_start(name, conf, &start_ops, &start_arg, lxcpath, backgrounded);
 }
+
+static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
+                                           const char *name)
+{
+       char destroy[MAXPATHLEN];
+       bool bret = true;
+       int ret = 0;
+       struct lxc_container *c;
+       if (handler->conf->rootfs.path && handler->conf->rootfs.mount) {
+               bret = do_destroy_container(handler->conf);
+               if (!bret) {
+                       ERROR("Error destroying rootfs for %s", name);
+                       return;
+               }
+       }
+       INFO("Destroyed rootfs for %s", name);
+
+       ret = snprintf(destroy, MAXPATHLEN, "%s/%s", handler->lxcpath, name);
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("Error printing path for %s", name);
+               ERROR("Error destroying directory for %s", name);
+               return;
+       }
+
+       c = lxc_container_new(name, handler->lxcpath);
+       if (c) {
+               if (container_disk_lock(c)) {
+                       INFO("Could not update lxc_snapshots file");
+                       lxc_container_put(c);
+               } else {
+                       mod_all_rdeps(c, false);
+                       container_disk_unlock(c);
+                       lxc_container_put(c);
+               }
+       }
+
+       if (am_unpriv())
+               ret = userns_exec_1(handler->conf, lxc_rmdir_onedev_wrapper, destroy);
+       else
+               ret = lxc_rmdir_onedev(destroy, NULL);
+
+       if (ret < 0) {
+               ERROR("Error destroying directory for %s", name);
+               return;
+       }
+       INFO("Destroyed directory for %s", name);
+}
+
+static int lxc_rmdir_onedev_wrapper(void *data)
+{
+       char *arg = (char *) data;
+       return lxc_rmdir_onedev(arg, NULL);
+}
+
+static bool do_destroy_container(struct lxc_conf *conf) {
+       if (am_unpriv()) {
+               if (userns_exec_1(conf, bdev_destroy_wrapper, conf) < 0)
+                       return false;
+               return true;
+       }
+       return bdev_destroy(conf);
+}
index 52e02ae..f06d302 100644 (file)
@@ -27,6 +27,7 @@
 #include <errno.h>
 #include <fcntl.h>
 
+#include "sync.h"
 #include "log.h"
 #include "start.h"
 
@@ -46,6 +47,12 @@ static int __sync_wait(int fd, int sequence)
        if (!ret)
                return 0;
 
+       if (sync == LXC_SYNC_ERROR) {
+               ERROR("An error occurred in another process "
+                     "(expected sequence number %d)", sequence);
+               return -1;
+       }
+
        if (sync != sequence) {
                ERROR("invalid sequence number %d. expected %d",
                      sync, sequence);
index 930fcb3..d0aee6f 100644 (file)
@@ -32,6 +32,7 @@ enum {
        LXC_SYNC_POST_CGROUP,
        LXC_SYNC_RESTART,
        LXC_SYNC_POST_RESTART,
+       LXC_SYNC_ERROR = -1 /* Used to report errors from another process */
 };
 
 int lxc_sync_init(struct lxc_handler *handler);
index d9e769d..61567e3 100644 (file)
 
 #include "config.h"
 
+#include <assert.h>
+#include <dirent.h>
 #include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include <fcntl.h>
+#include <libgen.h>
 #include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/vfs.h>
-#include <sys/stat.h>
+#include <unistd.h>
 #include <sys/mman.h>
-#include <sys/param.h>
 #include <sys/mount.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <libgen.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 #include <sys/wait.h>
-#include <assert.h>
-#include <sys/prctl.h>
 
-#include "utils.h"
 #include "log.h"
 #include "lxclock.h"
 #include "namespace.h"
+#include "utils.h"
 
 #ifndef PR_SET_MM
 #define PR_SET_MM 35
@@ -69,7 +69,7 @@ struct prctl_mm_map {
         uint64_t   *auxv;
         uint32_t   auxv_size;
         uint32_t   exe_fd;
-};              
+};
 #endif
 
 #ifndef O_PATH
@@ -1185,6 +1185,11 @@ bool file_exists(const char *f)
        return stat(f, &statbuf) == 0;
 }
 
+bool cgns_supported(void)
+{
+       return file_exists("/proc/self/ns/cgroup");
+}
+
 /* historically lxc-init has been under /usr/lib/lxc and under
  * /usr/lib/$ARCH/lxc.  It now lives as $prefix/sbin/init.lxc.
  */
@@ -1349,6 +1354,7 @@ char *get_template_path(const char *t)
  */
 int setproctitle(char *title)
 {
+       static char *proctitle = NULL;
        char buf[2048], *tmp;
        FILE *f;
        int i, len, ret = 0;
@@ -1413,28 +1419,21 @@ int setproctitle(char *title)
         * want to have room for it. */
        len = strlen(title) + 1;
 
-       /* We're truncating the environment, so we should use at most the
-        * length of the argument + environment for the title. */
-       if (len > env_end - arg_start) {
-               arg_end = env_end;
-               len = env_end - arg_start;
-               title[len-1] = '\0';
-       } else {
-               /* Only truncate the environment if we're actually going to
-                * overwrite part of it. */
-               if (len >= arg_end - arg_start) {
-                       env_start = env_end;
-               }
-
-               arg_end = arg_start + len;
-
-               /* check overflow */
-               if (arg_end < len || arg_end < arg_start) {
+       /* If we don't have enough room by just overwriting the old proctitle,
+        * let's allocate a new one.
+        */
+       if (len > arg_end - arg_start) {
+               void *m;
+               m = realloc(proctitle, len);
+               if (!m)
                        return -1;
-               }
+               proctitle = m;
 
+               arg_start = (unsigned long) proctitle;
        }
 
+       arg_end = arg_start + len;
+
        brk_val = syscall(__NR_brk, 0);
 
        prctl_map = (struct prctl_mm_map) {
@@ -1458,7 +1457,7 @@ int setproctitle(char *title)
        if (ret == 0)
                strcpy((char*)arg_start, title);
        else
-               SYSERROR("setting cmdline failed");
+               INFO("setting cmdline failed - %s", strerror(errno));
 
        return ret;
 }
@@ -1576,7 +1575,7 @@ static int open_without_symlink(const char *target, const char *prefix_skip)
        fulllen = strlen(target);
 
        /* make sure prefix-skip makes sense */
-       if (prefix_skip) {
+       if (prefix_skip && strlen(prefix_skip) > 0) {
                curlen = strlen(prefix_skip);
                if (!is_subdir(target, prefix_skip, curlen)) {
                        ERROR("WHOA there - target '%s' didn't start with prefix '%s'",
@@ -1622,8 +1621,6 @@ static int open_without_symlink(const char *target, const char *prefix_skip)
                        errno = saved_errno;
                        if (errno == ELOOP)
                                SYSERROR("%s in %s was a symbolic link!", nextpath, target);
-                       else
-                               SYSERROR("Error examining %s in %s", nextpath, target);
                        goto out;
                }
        }
@@ -1668,8 +1665,11 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
 
        destfd = open_without_symlink(dest, rootfs);
        if (destfd < 0) {
-               if (srcfd != -1)
+               if (srcfd != -1) {
+                       saved_errno = errno;
                        close(srcfd);
+                       errno = saved_errno;
+               }
                return destfd;
        }
 
@@ -1705,6 +1705,8 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
  *
  * Returns < 0 on failure, 0 if the correct proc was already mounted
  * and 1 if a new proc was mounted.
+ *
+ * NOTE: not to be called from inside the container namespace!
  */
 int mount_proc_if_needed(const char *rootfs)
 {
@@ -1738,29 +1740,101 @@ int mount_proc_if_needed(const char *rootfs)
        return 0;
 
 domount:
-       if (safe_mount("proc", path, "proc", 0, NULL, rootfs) < 0)
+       if (!strcmp(rootfs,"")) /* rootfs is NULL */
+               ret = mount("proc", path, "proc", 0, NULL);
+       else
+               ret = safe_mount("proc", path, "proc", 0, NULL, rootfs);
+
+       if (ret < 0)
                return -1;
+
        INFO("Mounted /proc in container for security transition");
        return 1;
 }
 
-int null_stdfds(void)
+int open_devnull(void)
 {
-       int fd, ret = -1;
+       int fd = open("/dev/null", O_RDWR);
+
+       if (fd < 0)
+               SYSERROR("Can't open /dev/null");
 
-       fd = open("/dev/null", O_RDWR);
+       return fd;
+}
+
+int set_stdfds(int fd)
+{
        if (fd < 0)
                return -1;
 
        if (dup2(fd, 0) < 0)
-               goto err;
+               return -1;
        if (dup2(fd, 1) < 0)
-               goto err;
+               return -1;
        if (dup2(fd, 2) < 0)
-               goto err;
+               return -1;
+
+       return 0;
+}
+
+int null_stdfds(void)
+{
+       int ret = -1;
+       int fd = open_devnull();
+
+       if (fd >= 0) {
+               ret = set_stdfds(fd);
+               close(fd);
+       }
 
-       ret = 0;
-err:
-       close(fd);
        return ret;
 }
+
+/*
+ * Return the number of lines in file @fn, or -1 on error
+ */
+int lxc_count_file_lines(const char *fn)
+{
+       FILE *f;
+       char *line = NULL;
+       size_t sz = 0;
+       int n = 0;
+
+       f = fopen_cloexec(fn, "r");
+       if (!f)
+               return -1;
+
+       while (getline(&line, &sz, f) != -1) {
+               n++;
+       }
+       free(line);
+       fclose(f);
+       return n;
+}
+
+void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
+                 off_t offset)
+{
+       void *tmp = NULL, *overlap = NULL;
+
+       /* We establish an anonymous mapping that is one byte larger than the
+        * underlying file. The pages handed to us are zero filled. */
+       tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if (tmp == MAP_FAILED)
+               return tmp;
+
+       /* Now we establish a fixed-address mapping starting at the address we
+        * received from our anonymous mapping and replace all bytes excluding
+        * the additional \0-byte with the file. This allows us to use normal
+        * string-handling functions. */
+       overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
+       if (overlap == MAP_FAILED)
+               munmap(tmp, length + 1);
+
+       return overlap;
+}
+
+int lxc_strmunmap(void *addr, size_t length)
+{
+       return munmap(addr, length + 1);
+}
index 059026f..22161cb 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef __LXC_UTILS_H
 #define __LXC_UTILS_H
 
+#include "config.h"
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -31,7 +33,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "initutils.h"
 
 /* returns 1 on success, 0 if there were any failures */
@@ -252,6 +253,14 @@ extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
 extern size_t lxc_array_len(void **array);
 
 extern void **lxc_append_null_to_array(void **array, size_t count);
+
+/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
+ * normal string-handling functions can be used on the buffer. */
+extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
+                        off_t offset);
+/* munmap() wrapper. Use it to free memory mmap()ed with lxc_strmmap(). */
+extern int lxc_strmunmap(void *addr, size_t length);
+
 //initialize rand with urandom
 extern int randseed(bool);
 
@@ -273,6 +282,7 @@ int detect_shared_rootfs(void);
 int detect_ramfs_rootfs(void);
 char *on_path(char *cmd, const char *rootfs);
 bool file_exists(const char *f);
+bool cgns_supported(void);
 char *choose_init(const char *rootfs);
 int print_to_file(const char *file, const char *content);
 bool switch_to_ns(pid_t pid, const char *ns);
@@ -282,5 +292,8 @@ int setproctitle(char *title);
 int safe_mount(const char *src, const char *dest, const char *fstype,
                unsigned long flags, const void *data, const char *rootfs);
 int mount_proc_if_needed(const char *rootfs);
+int open_devnull(void);
+int set_stdfds(int fd);
 int null_stdfds(void);
+int lxc_count_file_lines(const char *fn);
 #endif /* __LXC_UTILS_H */
index 512185c..b3f92d0 100644 (file)
 #ifndef __LXC_VERSION_H
 #define __LXC_VERSION_H
 
-#define LXC_VERSION_MAJOR 1
-#define LXC_VERSION_MINOR 1
-#define LXC_VERSION_MICRO 5
-#define LXC_VERSION "1.1.5"
+#define LXC_VERSION_MAJOR 2
+#define LXC_VERSION_MINOR 0
+#define LXC_VERSION_MICRO 0
+#define LXC_VERSION_ABI "1.2.0"
+#define LXC_VERSION "2.0.0"
 
 #endif
index 803a46e..cd1b6eb 100644 (file)
@@ -26,6 +26,7 @@
 #define LXC_VERSION_MAJOR @LXC_VERSION_MAJOR@
 #define LXC_VERSION_MINOR @LXC_VERSION_MINOR@
 #define LXC_VERSION_MICRO @LXC_VERSION_MICRO@
+#define LXC_VERSION_ABI "@LXC_VERSION_ABI@"
 #define LXC_VERSION "@LXC_VERSION@"
 
 #endif
index 69b7fd1..b14828e 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,13 +88,12 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/python-lxc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/setup.py.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = setup.py
@@ -109,6 +118,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/setup.py.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -161,6 +171,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -174,6 +185,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -265,6 +277,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -297,7 +310,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/python-lxc/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu src/python-lxc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -468,6 +480,8 @@ uninstall-am:
        maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
        pdf-am ps ps-am tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_PYTHON_TRUE@all:
 @ENABLE_PYTHON_TRUE@   $(PYTHON) setup.py build
index 2abbb43..eab4f46 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 #
 # api_test.py: Test/demo of the python3-lxc API
 #
index 89c3df7..8e07f15 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 #
 # pyconsole-vte: Example program showing use of console functions
 #                in the lxc python binding
index d47b00b..a9238a0 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 #
 # pyconsole: Example program showing use of console functions
 #            in the lxc python binding
index 77d9690..151d8fa 100644 (file)
@@ -117,6 +117,12 @@ struct lxc_attach_python_payload {
 
 static int lxc_attach_python_exec(void* _payload)
 {
+    /* This function is the first one to be called after attaching to a
+     * container. As lxc_attach() calls fork() PyOS_AfterFork should be called
+     * in the new process if the Python interpreter will continue to be used.
+     */
+    PyOS_AfterFork();
+
     struct lxc_attach_python_payload *payload =
         (struct lxc_attach_python_payload *)_payload;
     PyObject *result = PyObject_CallFunctionObjArgs(payload->fn,
@@ -800,11 +806,11 @@ Container_create(Container *self, PyObject *args, PyObject *kwds)
     char** create_args = {NULL};
     PyObject *retval = NULL;
     PyObject *vargs = NULL;
+    char *bdevtype = NULL;
     int i = 0;
-    static char *kwlist[] = {"template", "flags", "args", NULL};
-
-    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|siO", kwlist,
-                                      &template_name, &flags, &vargs))
+    static char *kwlist[] = {"template", "flags", "bdevtype", "args", NULL};
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|sisO", kwlist,
+                                      &template_name, &flags, &bdevtype, &vargs))
         return NULL;
 
     if (vargs) {
@@ -820,7 +826,7 @@ Container_create(Container *self, PyObject *args, PyObject *kwds)
         }
     }
 
-    if (self->container->create(self->container, template_name, NULL, NULL,
+    if (self->container->create(self->container, template_name, bdevtype, NULL,
                                 flags, create_args))
         retval = Py_True;
     else
index d7b0670..30ebd1b 100644 (file)
@@ -205,7 +205,7 @@ class Container(_lxc.Container):
 
         return _lxc.Container.set_config_item(self, key, value)
 
-    def create(self, template=None, flags=0, args=()):
+    def create(self, template=None, flags=0, args=(), bdevtype=None):
         """
             Create a new rootfs for the container.
 
@@ -217,22 +217,19 @@ class Container(_lxc.Container):
             "args" (optional) is a tuple of arguments to pass to the
             template. It can also be provided as a dict.
         """
-
         if isinstance(args, dict):
-            template_args = []
+            tmp_args = []
             for item in args.items():
-                template_args.append("--%s" % item[0])
-                template_args.append("%s" % item[1])
-        else:
-            template_args = args
-
+                tmp_args.append("--%s" % item[0])
+                tmp_args.append("%s" % item[1])
+        template_args = {}
         if template:
-            return _lxc.Container.create(self, template=template,
-                                         flags=flags,
-                                         args=tuple(template_args))
-        else:
-            return _lxc.Container.create(self, flags=flags,
-                                         args=tuple(template_args))
+           template_args['template'] = template
+        template_args['flags'] = flags
+        template_args['args'] = tuple(tmp_args)
+        if bdevtype:
+            template_args['bdevtype'] = bdevtype
+        return _lxc.Container.create(self, **template_args)
 
     def clone(self, newname, config_path=None, flags=0, bdevtype=None,
               bdevdata=None, newsize=0, hookargs=()):
index 3b4b1fe..fcb676e 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 #
 # python-lxc: Python bindings for LXC
 #
index 8af9baa..68141f9 100644 (file)
@@ -48,12 +48,15 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
        lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove \
        lxc-test-apparmor
 
-bin_SCRIPTS = lxc-test-autostart lxc-test-cloneconfig lxc-test-createconfig
+bin_SCRIPTS = lxc-test-automount lxc-test-autostart lxc-test-cloneconfig \
+       lxc-test-createconfig
 
 if DISTRO_UBUNTU
 bin_SCRIPTS += \
+       lxc-test-lxc-attach \
        lxc-test-apparmor-mount \
        lxc-test-checkpoint-restore \
+       lxc-test-snapdeps \
        lxc-test-symlink \
        lxc-test-ubuntu \
        lxc-test-unpriv \
@@ -76,11 +79,14 @@ EXTRA_DIST = \
        list.c \
        locktests.c \
        lxcpath.c \
+       lxc-test-lxc-attach \
+       lxc-test-automount \
        lxc-test-autostart \
        lxc-test-apparmor-mount \
        lxc-test-checkpoint-restore \
        lxc-test-cloneconfig \
        lxc-test-createconfig \
+       lxc-test-snapdeps \
        lxc-test-symlink \
        lxc-test-ubuntu \
        lxc-test-unpriv \
index 5ceb65b..2ca985f 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -103,21 +113,22 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@    lxc-test-device-add-remove$(EXEEXT) \
 @ENABLE_TESTS_TRUE@    lxc-test-apparmor$(EXEEXT)
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@am__append_3 = \
+@DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-lxc-attach \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-apparmor-mount \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-checkpoint-restore \
+@DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-snapdeps \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-symlink \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-ubuntu \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-unpriv \
 @DISTRO_UBUNTU_TRUE@@ENABLE_TESTS_TRUE@        lxc-test-usernic
 
 subdir = src/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-test-usernic.in $(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-test-usernic
@@ -362,6 +373,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-test-usernic.in \
+       $(top_srcdir)/config/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -414,6 +427,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -427,6 +441,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -518,6 +533,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -556,7 +572,7 @@ top_srcdir = @top_srcdir@
 @ENABLE_TESTS_TRUE@    -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
 @ENABLE_TESTS_TRUE@    -DRUNTIME_PATH=\"$(RUNTIME_PATH)\" \
 @ENABLE_TESTS_TRUE@    $(am__append_1) $(am__append_2)
-@ENABLE_TESTS_TRUE@bin_SCRIPTS = lxc-test-autostart \
+@ENABLE_TESTS_TRUE@bin_SCRIPTS = lxc-test-automount lxc-test-autostart \
 @ENABLE_TESTS_TRUE@    lxc-test-cloneconfig lxc-test-createconfig \
 @ENABLE_TESTS_TRUE@    $(am__append_3)
 EXTRA_DIST = \
@@ -573,11 +589,14 @@ EXTRA_DIST = \
        list.c \
        locktests.c \
        lxcpath.c \
+       lxc-test-lxc-attach \
+       lxc-test-automount \
        lxc-test-autostart \
        lxc-test-apparmor-mount \
        lxc-test-checkpoint-restore \
        lxc-test-cloneconfig \
        lxc-test-createconfig \
+       lxc-test-snapdeps \
        lxc-test-symlink \
        lxc-test-ubuntu \
        lxc-test-unpriv \
@@ -603,7 +622,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu src/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -1033,6 +1051,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS
        mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
        uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index ee827c1..af03862 100644 (file)
@@ -23,6 +23,7 @@
 #include "lxc/utils.h"
 #include "lxc/lsm/lsm.h"
 
+#include <sys/types.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <errno.h>
 static const char *lsm_config_key = NULL;
 static const char *lsm_label = NULL;
 
+bool file_exists(const char *f)
+{
+       struct stat statbuf;
+
+       return stat(f, &statbuf) == 0;
+}
+
 static void test_lsm_detect(void)
 {
        if (lsm_enabled()) {
@@ -48,7 +56,10 @@ static void test_lsm_detect(void)
                }
                else if (!strcmp(lsm_name(), "AppArmor")) {
                        lsm_config_key = "lxc.aa_profile";
-                       lsm_label      = "lxc-container-default";
+                       if (file_exists("/proc/self/ns/cgroup"))
+                               lsm_label      = "lxc-container-default-cgns";
+                       else
+                               lsm_label      = "lxc-container-default";
                }
                else {
                        TSTERR("unknown lsm %s enabled, add test code here", lsm_name());
index 943583c..9a9ae59 100644 (file)
@@ -88,6 +88,32 @@ int main(int argc, char *argv[])
        }
        printf("lxc.arch returned %d %s\n", ret, v2);
 
+       if (!c->set_config_item(c, "lxc.init_uid", "100")) {
+               fprintf(stderr, "%d: failed to set init_uid\n", __LINE__);
+               ret = 1;
+               goto out;
+       }
+       ret = c->get_config_item(c, "lxc.init_uid", v2, 255);
+       if (ret < 0) {
+               fprintf(stderr, "%d: get_config_item(lxc.init_uid) returned %d\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("lxc.init_uid returned %d %s\n", ret, v2);
+
+       if (!c->set_config_item(c, "lxc.init_gid", "100")) {
+               fprintf(stderr, "%d: failed to set init_gid\n", __LINE__);
+               ret = 1;
+               goto out;
+       }
+       ret = c->get_config_item(c, "lxc.init_gid", v2, 255);
+       if (ret < 0) {
+               fprintf(stderr, "%d: get_config_item(lxc.init_gid) returned %d\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("lxc.init_gid returned %d %s\n", ret, v2);
+
 #define HNAME "hostname1"
        // demonstrate proper usage:
        char *alloced;
@@ -314,8 +340,8 @@ int main(int argc, char *argv[])
                ret = 1;
                goto out;
        }
-       if (!c->clear_config_item(c, "lxc.mount.entries")) {
-               fprintf(stderr, "%d: failed clearing lxc.mount.entries\n", __LINE__);
+       if (!c->clear_config_item(c, "lxc.mount.entry")) {
+               fprintf(stderr, "%d: failed clearing lxc.mount.entry\n", __LINE__);
                ret = 1;
                goto out;
        }
index e3712c7..3fd3f5a 100755 (executable)
 
 set -e
 
+if [ -f /proc/self/ns/cgroup ]; then
+       default_profile="lxc-container-default-cgns (enforce)"
+else
+       default_profile="lxc-container-default (enforce)"
+fi
+
 FAIL() {
        echo -n "Failed " >&2
        echo "$*" >&2
@@ -125,6 +131,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R $TUSER: $d/lxctest
                echo $$ > $d/lxctest/tasks
@@ -144,7 +151,7 @@ run_cmd lxc-start -n $cname -d
 run_cmd lxc-wait -n $cname -s RUNNING
 pid=`run_cmd lxc-info -p -H -n $cname`
 profile=`cat /proc/$pid/attr/current`
-if [ "x$profile" != "xlxc-container-default (enforce)" ]; then
+if [ "x$profile" != "x${default_profile}" ]; then
        echo "FAIL: confined container was in profile $profile"
        exit 1
 fi
@@ -203,7 +210,7 @@ if [ "$pid" = "-1" ]; then
        exit 1
 fi
 profile=`cat /proc/$pid/attr/current`
-if [ "x$profile" != "xlxc-container-default (enforce)" ]; then
+if [ "x$profile" != "x${default_profile}" ]; then
        echo "FAIL: confined container was in profile $profile"
        exit 1
 fi
diff --git a/src/tests/lxc-test-automount b/src/tests/lxc-test-automount
new file mode 100644 (file)
index 0000000..4505375
--- /dev/null
@@ -0,0 +1,220 @@
+#!/bin/bash
+
+# lxc: linux Container library
+
+# Authors:
+# Serge Hallyn <serge.hallyn@ubuntu.com>
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# At the moment this only tests cgroup automount.  Testing proc and
+# sys automounts would be worthwhile.
+
+[ -f /proc/self/ns/cgroup ] && exit 0
+
+# cgmanager doesn't do the same cgroup filesystem mounting
+cgm ping && exit 0
+
+set -ex
+
+cleanup() {
+       set +e
+       rmdir /sys/fs/cgroup/freezer/xx
+       lxc-destroy -n lxc-test-automount -f
+       if [ $PHASE != "done" ]; then
+               echo "automount test failed at $PHASE"
+               exit 1
+       fi
+       echo "automount test passed"
+       exit 0
+}
+
+PHASE=setup
+trap cleanup EXIT
+
+rmdir /sys/fs/cgroup/freezer/xx || true
+lxc-destroy -n lxc-test-automount -f || true
+lxc-create -t busybox -n lxc-test-automount
+
+PHASE=no-cgroup
+echo "Starting phase $PHASE"
+config=/var/lib/lxc/lxc-test-automount/config
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = proc:mixed sys:mixed" >> $config
+
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 0 ]
+
+# Tests are as follows:
+# 1. check that freezer controller is mounted
+# 2. check that it is cgroupfs for cgroup-full (/cgroup.procs exists) or
+#    tmpfs for cgroup
+# 3. check that root cgroup dir is readonly or not (try mkdir)
+# 4. check that the container's cgroup dir is readonly or not
+# 5. check that the container's cgroup dir is cgroupfs (/cgroup.procs exists)
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:mixed
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:ro
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:ro proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:rw
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:rw proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/xx
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+# cgroup-full
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:mixed
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:mixed  proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:ro
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:ro proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xy || ro=1
+[ $ro -ne 0 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:rw
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:rw proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/xx
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+/proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -eq 1 ]
+
+PHASE=done
index 0f38369..4e51cc4 100755 (executable)
@@ -124,7 +124,7 @@ for f in $s/*.conf; do
        echo "Test $testnum starting ($f)"
        lxc-create -t busybox -f $f -n lxctestb
        touch $CONTAINER_PATH/x1
-       lxc-clone -s -o lxctestb -n lxctestb2
+       lxc-copy -s -n lxctestb -N lxctestb2
        # verify that # nics did not change
        verify_numnics
        # verify hwaddr, if any changed
diff --git a/src/tests/lxc-test-lxc-attach b/src/tests/lxc-test-lxc-attach
new file mode 100755 (executable)
index 0000000..664b028
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+# lxc: linux Container library
+
+# Authors:
+# Christian Brauner <christian.brauner@mailbox.org>
+#
+# This is a test script for the lxc-attach program. It tests whether I/O
+# redirection and pty allocation works correctly.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+set -e
+
+# NOTE:
+# lxc-attach allocates a pty on the host and attaches any standard file
+# descriptors that refer to a pty to it. Standard file descriptors which do not
+# refer to a pty are not attached. In order to determine whether lxc-attach
+# works correctly we test various methods of redirection on the host. E.g.:
+#
+#       lxc-attach -n busy -- hostname < /dev/null
+#
+# This is done to check whether the file descriptor that gets redirected to
+# /dev/null is (a) left alone and (b) that lxc-attach does not fail. When
+# lxc-attach fails we know that it's behavior has been altered, e.g. by trying
+# to attach a standard file descriptor that does not refer to a pty.
+# The small table preceeding each test case show which standard file descriptors
+# we expect to be attached to a pty and which we expect to be redirected. E.g.
+#
+#       stdin  --> attached to pty
+#       stdout --> attached to pty
+#       stderr --> attached to pty
+
+FAIL() {
+       echo -n "Failed " >&2
+       echo "$*" >&2
+        lxc-destroy -n busy -f
+       exit 1
+}
+
+# Create a container, start it and wait for it to be in running state.
+lxc-create -t busybox -n busy || FAIL "creating busybox container"
+lxc-start -n busy -d || FAIL "starting busybox container"
+lxc-wait -n busy -s RUNNING || FAIL "waiting for busybox container to run"
+
+# stdin  --> attached to pty
+# stdout --> attached to pty
+# stderr --> attached to pty
+attach=$(lxc-attach -n busy -- hostname || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " simple attach"
+fi
+
+# stdin  --> /dev/null
+# stdout --> attached to pty
+# stderr --> attached to pty
+attach=$(lxc-attach -n busy -- hostname < /dev/null || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " lxc-attach -n busy -- hostname < /dev/null"
+fi
+
+# stdin  --> attached to pty
+# stdout --> /dev/null
+# stderr --> attached to pty
+attach=$(lxc-attach -n busy -- hostname > /dev/null || FAIL " to allocate or setup pty")
+if [ -n "$attach" ]; then
+        FAIL " lxc-attach -n busy -- hostname > /dev/null"
+fi
+
+# stdin  --> attached to pty
+# stdout --> attached to pty
+# stderr --> /dev/null
+attach=$(lxc-attach -n busy -- hostname 2> /dev/null || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
+fi
+
+# stdin  --> /dev/null
+# stdout --> attached to pty
+# stderr --> /dev/null
+attach=$(lxc-attach -n busy -- hostname 2> /dev/null < /dev/null || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
+fi
+
+# Use a synthetic reproducer in container to produce output on stderr. stdout on
+# the host gets redirect to /dev/null. We should still be able to receive
+# containers output on stderr on the host. (The command is run in a subshell.
+# This allows us to redirect stderr to stdout for the subshell and capture the
+# output in the attach variable.)
+# stdin  --> attached to pty
+# stdout --> /dev/null
+# stderr --> attached to pty
+attach=$( ( lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null ) 2>&1 || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null"
+fi
+
+# Use a synthetic reproducer in container to produce output on stderr. stderr on
+# the host gets redirect to /dev/null. We should not receive output on stderr on
+# the host. (The command is run in a subshell. This allows us to redirect stderr
+# to stdout for the subshell and capture the output in the attach variable.)
+# stdin  --> attached to pty
+# stdout --> attach to pty
+# stderr --> /dev/null
+attach=$( ( lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null ) 2>&1 || FAIL " to allocate or setup pty")
+if [ -n "$attach" ]; then
+        FAIL " lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null"
+fi
+
+
+# stdin  --> attached to pty
+# stdout --> /dev/null
+# stderr --> attached to pty
+# (As we expect the exit code of the command to be 1 we ignore it.)
+attach=$(lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null || true)
+if [ -n "$attach" ]; then
+        FAIL " lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null"
+fi
+
+
+# - stdin  --> attached to pty
+# - stdout --> attached to pty
+# - stderr --> /dev/null
+# (As we expect the exit code of the command to be 1 we ignore it.)
+attach=$(lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null || true)
+if [ -z "$attach" ]; then
+        FAIL " lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null"
+fi
+
+# stdin  --> $in
+# stdout --> attached to pty
+# stderr --> attached to pty
+attach=$(echo hostname | lxc-attach -n busy -- || FAIL " to allocate or setup pty")
+if [ "$attach" != "busy" ]; then
+        FAIL " echo hostname | lxc-attach -n busy --"
+fi
+
+# stdin  --> attached to pty
+# stdout --> $out
+# stderr --> $err
+out=$(mktemp /tmp/out_XXXX)
+err=$(mktemp /tmp/err_XXXX)
+trap "rm -f $out $err" EXIT INT QUIT PIPE
+lxc-attach -n busy -- sh -c 'echo OUT; echo ERR >&2' > $out 2> $err || FAIL " to allocate or setup pty"
+outcontent=$(cat $out)
+errcontent=$(cat $err)
+if [ "$outcontent" != "OUT" ] || [ "$errcontent" != "ERR" ]; then
+        FAIL " lxc-attach -n busy -- sh -c 'echo OUT; echo ERR >&2' > $out 2> $err"
+fi
+
+# stdin  --> $in
+# stdout --> $out
+# stderr --> $err
+# (As we expect the exit code of the command to be 1 we ignore it.)
+out=$(mktemp /tmp/out_XXXX)
+err=$(mktemp /tmp/err_XXXX)
+trap "rm -f $out $err" EXIT INT QUIT PIPE
+echo "hostname; rm" | lxc-attach -n busy > $out 2> $err || true
+outcontent=$(cat $out)
+errcontent=$(cat $err)
+if [ "$outcontent" != "busy" ] || [ -z "$errcontent" ]; then
+        FAIL " echo 'hostname; rm' | lxc-attach -n busy > $out 2> $err"
+fi
+
+lxc-destroy -n busy -f
+
+exit 0
diff --git a/src/tests/lxc-test-snapdeps b/src/tests/lxc-test-snapdeps
new file mode 100644 (file)
index 0000000..3f95bba
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+# lxc: linux Container library
+
+# Authors:
+# Serge Hallyn <serge.hallyn@ubuntu.com>
+#
+# This is a test for dependency between snapshots
+#
+# When container c2 is created as an overlayfs clone of c1, then
+# we record it as such, because c1 cannot be deleted until c2 is
+# deleted.  Once c2 is deleted, c1 should be delete-able.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This test assumes an Ubuntu host
+
+set -e
+
+if ! grep -q overlay /proc/filesystems; then
+       echo "Not running this test as overlay is not available"
+       exit 0
+fi
+
+cleanup() {
+       for i in `seq 1 20`; do
+               lxc-destroy -n snapdeptest$i > /dev/null 2>&1 || true
+       done
+       lxc-destroy -n snapdeptest > /dev/null 2>&1 || true
+}
+
+verify_deps() {
+       n=$1
+       m=`wc -l /var/lib/lxc/snapdeptest/lxc_snapshots | awk '{ print $1 }'`
+       [ $((n*2)) -eq $m ]
+}
+
+cleanup
+
+trap cleanup EXIT SIGHUP SIGINT SIGTERM
+
+lxc-create -t busybox -n snapdeptest
+lxc-copy -s -n snapdeptest -N snapdeptest1
+fail=0
+lxc-destroy -n snapdeptest || fail=1
+if [ $fail -eq 0 ]; then
+       echo "FAIL: clone did not prevent deletion"
+       false
+fi
+
+for i in `seq 2 20`; do
+       lxc-copy -s -n snapdeptest -N snapdeptest$i
+done
+
+verify_deps 20
+
+lxc-destroy -n snapdeptest1
+
+verify_deps 19
+
+lxc-destroy -n snapdeptest20
+
+verify_deps 18
+
+for i in `seq 2 19`; do
+       lxc-destroy -n snapdeptest$i
+done
+
+lxc-destroy -n snapdeptest
+
+echo "Snapshot clone dependency test passed"
+exit 0
index ff716bc..dc06804 100755 (executable)
@@ -65,7 +65,9 @@ for template in ubuntu ubuntu-cloud; do
        # Check apparmor
        lxcpid=`lxc-info -n $name -p -H`
        aa=`cat /proc/$lxcpid/attr/current`
-       if [ "$aa" != "lxc-container-default-with-nesting (enforce)" -a "$aa" != "lxc-container-default (enforce)" ]; then
+       if [ "$aa" != "lxc-container-default-with-nesting (enforce)" -a \
+                       "$aa" != "lxc-container-default-cgns (enforce)" -a \
+                       "$aa" != "lxc-container-default (enforce)" ]; then
                FAIL " to correctly set apparmor profile (profile is \"$aa\")"
        fi
        lxc-stop -n $name -k
index 93c91a9..f3a7910 100755 (executable)
@@ -112,6 +112,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R $TUSER: $d/lxctest
                echo $$ > $d/lxctest/tasks
@@ -125,16 +126,22 @@ run_cmd mkdir -p $HDIR/.cache/lxc
     chown -R $TUSER: $HDIR/.cache/lxc
 
 run_cmd lxc-create -t download -n c1 -- -d ubuntu -r trusty -a $ARCH
-run_cmd lxc-start -n c1 -d
 
-p1=$(run_cmd lxc-info -n c1 -p -H)
-[ "$p1" != "-1" ] || { echo "Failed to start container c1"; false; }
+# Make sure we can start it - twice
 
-run_cmd lxc-info -n c1
-run_cmd lxc-attach -n c1 -- /bin/true
+for count in `seq 1 2`; do
+    run_cmd lxc-start -n c1 -d
+
+    p1=$(run_cmd lxc-info -n c1 -p -H)
+    [ "$p1" != "-1" ] || { echo "Failed to start container c1 (run $count)"; false; }
+
+    run_cmd lxc-info -n c1
+    run_cmd lxc-attach -n c1 -- /bin/true
+
+    run_cmd lxc-stop -n c1
+done
 
-run_cmd lxc-stop -n c1
-run_cmd lxc-clone -s -o c1 -n c2
+run_cmd lxc-copy -s -n c1 -N c2
 run_cmd lxc-start -n c2 -d
 p1=$(run_cmd lxc-info -n c2 -p -H)
 [ "$p1" != "-1" ] || { echo "Failed to start container c2"; false; }
index 75dd984..6a5650d 100755 (executable)
@@ -104,6 +104,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R usernic-user: $d/lxctest
                echo $$ > $d/lxctest/tasks
@@ -136,8 +137,11 @@ run_cmd "lxc-create -t download -n b1 -- -d ubuntu -r trusty -a $ARCH"
 run_cmd "lxc-start -n b1 -d"
 p1=$(run_cmd "lxc-info -n b1 -p -H")
 
+lxcpath=/home/usernic-user/.local/share/lxc
+lxcname=b1
+
 # Assign one veth, should fail as no allowed entries yet
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx1"; then
+if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx1"; then
        echo "FAIL: able to create nic with no entries"
        exit 1
 fi
@@ -148,24 +152,24 @@ sed -i '/^usernic-user/d' /etc/lxc/lxc-usernet
 echo "usernic-user veth usernic-br0 2" >> /etc/lxc/lxc-usernet
 
 # Assign one veth to second bridge, should fail
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br1 xx1"; then
+if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br1 xx1"; then
        echo "FAIL: able to create nic with no entries"
        exit 1
 fi
 
 # Assign two veths, should succeed
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx2"; then
+if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx2"; then
        echo "FAIL: unable to create first nic"
        exit 1
 fi
 
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx3"; then
+if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx3"; then
        echo "FAIL: unable to create second nic"
        exit 1
 fi
 
 # Assign one more veth, should fail.
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx4"; then
+if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx4"; then
        echo "FAIL: able to create third nic"
        exit 1
 fi
@@ -175,7 +179,7 @@ run_cmd "lxc-stop -n b1 -k"
 run_cmd "lxc-start -n b1 -d"
 p1=$(run_cmd "lxc-info -n b1 -p -H")
 
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx5"; then
+if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx5"; then
        echo "FAIL: unable to create nic after destroying the old"
        cleanup 1
 fi
@@ -188,7 +192,7 @@ lxc-start -n usernic-c1 -d
 p2=$(lxc-info -n usernic-c1 -p -H)
 
 # assign veth to it - should fail
-if run_cmd "$LXC_USER_NIC $p2 veth usernic-br0 xx6"; then
+if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p2 veth usernic-br0 xx6"; then
        echo "FAIL: able to attach nic to root-owned container"
        cleanup 1
 fi
index ac870a1..17a9f8c 100644 (file)
@@ -15,6 +15,8 @@ templates_SCRIPTS = \
        lxc-opensuse \
        lxc-oracle \
        lxc-plamo \
+       lxc-slackware \
        lxc-sshd \
        lxc-ubuntu \
-       lxc-ubuntu-cloud
+       lxc-ubuntu-cloud \
+       lxc-sparclinux
index 4bb5918..8b063dc 100644 (file)
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,27 +89,19 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = templates
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-       $(srcdir)/lxc-alpine.in $(srcdir)/lxc-altlinux.in \
-       $(srcdir)/lxc-archlinux.in $(srcdir)/lxc-busybox.in \
-       $(srcdir)/lxc-centos.in $(srcdir)/lxc-cirros.in \
-       $(srcdir)/lxc-debian.in $(srcdir)/lxc-download.in \
-       $(srcdir)/lxc-fedora.in $(srcdir)/lxc-gentoo.in \
-       $(srcdir)/lxc-openmandriva.in $(srcdir)/lxc-opensuse.in \
-       $(srcdir)/lxc-oracle.in $(srcdir)/lxc-plamo.in \
-       $(srcdir)/lxc-sshd.in $(srcdir)/lxc-ubuntu.in \
-       $(srcdir)/lxc-ubuntu-cloud.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \
        $(top_srcdir)/config/tls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = lxc-alpine lxc-altlinux lxc-archlinux lxc-busybox \
        lxc-centos lxc-cirros lxc-debian lxc-download lxc-fedora \
        lxc-gentoo lxc-openmandriva lxc-opensuse lxc-oracle lxc-plamo \
-       lxc-sshd lxc-ubuntu lxc-ubuntu-cloud
+       lxc-slackware lxc-sshd lxc-ubuntu lxc-ubuntu-cloud \
+       lxc-sparclinux
 CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -150,6 +152,16 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/lxc-alpine.in \
+       $(srcdir)/lxc-altlinux.in $(srcdir)/lxc-archlinux.in \
+       $(srcdir)/lxc-busybox.in $(srcdir)/lxc-centos.in \
+       $(srcdir)/lxc-cirros.in $(srcdir)/lxc-debian.in \
+       $(srcdir)/lxc-download.in $(srcdir)/lxc-fedora.in \
+       $(srcdir)/lxc-gentoo.in $(srcdir)/lxc-openmandriva.in \
+       $(srcdir)/lxc-opensuse.in $(srcdir)/lxc-oracle.in \
+       $(srcdir)/lxc-plamo.in $(srcdir)/lxc-slackware.in \
+       $(srcdir)/lxc-sparclinux.in $(srcdir)/lxc-sshd.in \
+       $(srcdir)/lxc-ubuntu-cloud.in $(srcdir)/lxc-ubuntu.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -202,6 +214,7 @@ LUA_LIBDIR = @LUA_LIBDIR@
 LUA_LIBS = @LUA_LIBS@
 LUA_SHAREDIR = @LUA_SHAREDIR@
 LUA_VERSION = @LUA_VERSION@
+LXCBINHOOKDIR = @LXCBINHOOKDIR@
 LXCHOOKDIR = @LXCHOOKDIR@
 LXCINITDIR = @LXCINITDIR@
 LXCPATH = @LXCPATH@
@@ -215,6 +228,7 @@ LXC_GLOBAL_CONF = @LXC_GLOBAL_CONF@
 LXC_USERNIC_CONF = @LXC_USERNIC_CONF@
 LXC_USERNIC_DB = @LXC_USERNIC_DB@
 LXC_VERSION = @LXC_VERSION@
+LXC_VERSION_ABI = @LXC_VERSION_ABI@
 LXC_VERSION_BASE = @LXC_VERSION_BASE@
 LXC_VERSION_BETA = @LXC_VERSION_BETA@
 LXC_VERSION_MAJOR = @LXC_VERSION_MAJOR@
@@ -306,6 +320,7 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 pyexecdir = @pyexecdir@
 pythondir = @pythondir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -330,9 +345,11 @@ templates_SCRIPTS = \
        lxc-opensuse \
        lxc-oracle \
        lxc-plamo \
+       lxc-slackware \
        lxc-sshd \
        lxc-ubuntu \
-       lxc-ubuntu-cloud
+       lxc-ubuntu-cloud \
+       lxc-sparclinux
 
 all: all-am
 
@@ -349,7 +366,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu templates/Makefile'; \
        $(am__cd) $(top_srcdir) && \
          $(AUTOMAKE) --gnu templates/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
          *config.status*) \
@@ -395,12 +411,16 @@ lxc-oracle: $(top_builddir)/config.status $(srcdir)/lxc-oracle.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-plamo: $(top_builddir)/config.status $(srcdir)/lxc-plamo.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-slackware: $(top_builddir)/config.status $(srcdir)/lxc-slackware.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-sshd: $(top_builddir)/config.status $(srcdir)/lxc-sshd.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-ubuntu: $(top_builddir)/config.status $(srcdir)/lxc-ubuntu.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 lxc-ubuntu-cloud: $(top_builddir)/config.status $(srcdir)/lxc-ubuntu-cloud.in
        cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+lxc-sparclinux: $(top_builddir)/config.status $(srcdir)/lxc-sparclinux.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 install-templatesSCRIPTS: $(templates_SCRIPTS)
        @$(NORMAL_INSTALL)
        @list='$(templates_SCRIPTS)'; test -n "$(templatesdir)" || list=; \
@@ -590,6 +610,8 @@ uninstall-am: uninstall-templatesSCRIPTS
        mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
        uninstall uninstall-am uninstall-templatesSCRIPTS
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 29c7b7c..18feda9 100644 (file)
 #!/bin/sh
+# vim: set ts=4:
+
+# Exit on error and treat unset variables as an error.
+set -eu
+
+#
+# LXC template for Alpine Linux 3+
+#
+
+# Note: Do not replace tabs with spaces, it would break heredocs!
+
+# Authors:
+# Jakub Jirutka <jakub@jirutka.cz>
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
-# Detect use under userns (unsupported)
-for arg in "$@"; do
-    [ "$arg" = "--" ] && break
-    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
-        echo "This template can't be used for unprivileged containers." 1>&2
-        echo "You may want to try the \"download\" template instead." 1>&2
-        exit 1
-    fi
-done
+
+#===========================  Constants  ============================#
 
 # Make sure the usual locations are in PATH
-PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
-export PATH
+export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+readonly LOCAL_STATE_DIR='@LOCALSTATEDIR@'
+readonly LXC_TEMPLATE_CONFIG='@LXCTEMPLATECONFIG@'
+readonly LXC_CACHE_DIR="${LXC_CACHE_PATH:-"$LOCAL_STATE_DIR/cache/lxc"}/alpine"
 
-key_sha256sums="9c102bcc376af1498d549b77bdbfa815ae86faa1d2d82f040e616b18ef2df2d4  alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
+# SHA256 checksums of GPG keys for APK.
+readonly APK_KEYS_SHA256="\
+9c102bcc376af1498d549b77bdbfa815ae86faa1d2d82f040e616b18ef2df2d4  alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
 2adcf7ce224f476330b5360ca5edb92fd0bf91c92d83292ed028d7c4e26333ab  alpine-devel@lists.alpinelinux.org-4d07755e.rsa.pub
 ebf31683b56410ecc4c00acd9f6e2839e237a3b62b5ae7ef686705c7ba0396a9  alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
 1bb2a846c0ea4ca9d0e7862f970863857fc33c32f5506098c636a62a726a847b  alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
 12f899e55a7691225603d6fb3324940fc51cd7f133e7ead788663c2b7eecb00c  alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub"
 
+readonly APK_KEYS_URI='http://alpinelinux.org/keys'
+readonly MIRRORS_LIST_URL='http://rsync.alpinelinux.org/alpine/MIRRORS.txt'
+
+: ${APK_KEYS_DIR:=/etc/apk/keys}
+if ! ls "$APK_KEYS_DIR"/alpine* >/dev/null 2>&1; then
+       APK_KEYS_DIR="$LXC_CACHE_DIR/bootstrap/keys"
+fi
+readonly APK_KEYS_DIR
+
+: ${APK:=$(command -v apk || true)}
+if [ ! -x "$APK" ]; then
+       APK="$LXC_CACHE_DIR/bootstrap/sbin/apk.static"
+fi
+readonly APK
+
+
+#========================  Helper Functions  ========================#
 
-get_static_apk () {
-    wget="wget -q -O -"
-    pkglist=alpine-keys:apk-tools-static
-    auto_repo_dir=
-
-    if [ -z "$repository" ]; then
-        url=http://wiki.alpinelinux.org/cgi-bin/dl.cgi
-       yaml_path="latest-stable/releases/$apk_arch/latest-releases.yaml"
-        if [ -z "$release" ]; then
-            echo -n "Determining the latest release... "
-            release=$($wget $url/$yaml_path | \
-               awk '$1 == "branch:" {print $2; exit 0}')
-            if [ -z "$release" ]; then
-                release=$($wget $url/.latest.$apk_arch.txt | \
-                    cut -d " " -f 3 | cut -d / -f 1 | uniq)
-            fi
-            if [ -z "$release" ]; then
-                echo failed
-                return 1
-            fi
-            echo $release
-        fi
-        auto_repo_dir=$release/main
-        repository=$url/$auto_repo_dir
-        pkglist=$pkglist:alpine-mirrors
-    fi
-
-    rootfs="$1"
-    echo "Using static apk from $repository/$apk_arch"
-    wget="$wget $repository/$apk_arch"
-
-    # parse APKINDEX to find the current versions
-    static_pkgs=$($wget/APKINDEX.tar.gz | \
-        tar -Oxz APKINDEX | \
-        awk -F: -v pkglist=$pkglist '
-            BEGIN { split(pkglist,pkg) }
-            $0 != "" { f[$1] = $2 }
-            $0 == "" { for (i in pkg)
-                           if (pkg[i] == f["P"])
-                               print(f["P"] "-" f["V"] ".apk") }')
-    [ "$static_pkgs" ] || return 1
-
-    mkdir -p "$rootfs" || return 1
-    for pkg in $static_pkgs; do
-        echo "Downloading $pkg"
-        $wget/$pkg | tar -xz -C "$rootfs"
-    done
-
-    # clean up .apk meta files
-    rm -f "$rootfs"/.[A-Z]*
-
-    # verify checksum of the key
-    keyname=$(echo $rootfs/sbin/apk.static.*.pub | sed 's/.*\.SIGN\.RSA\.//')
-    checksum=$(echo "$key_sha256sums" |  grep -w "$keyname")
-    if [ -z "$checksum" ]; then
-        echo "ERROR: checksum is missing for $keyname"
-        return 1
-    fi
-    (cd $rootfs/etc/apk/keys && echo "$checksum" | sha256sum -c -) || return 1
-
-    # verify the static apk binary signature
-    APK=$rootfs/sbin/apk.static
-    openssl dgst -sha1 -verify $rootfs/etc/apk/keys/$keyname \
-        -signature "$APK.SIGN.RSA.$keyname" "$APK" || return 1
-
-    if [ "$auto_repo_dir" ]; then
-        mirror_list=$rootfs/usr/share/alpine-mirrors/MIRRORS.txt
-        mirror_count=$(wc -l $mirror_list | cut -d " " -f 1)
-        random=$(hexdump -n 2 -e '/2 "%u"' /dev/urandom)
-        repository=$(sed $(expr $random % $mirror_count + 1)\!d \
-            $mirror_list)$auto_repo_dir
-        echo "Selecting mirror $repository"
-    fi
+usage() {
+       cat <<-EOF
+               Template specific options can be passed to lxc-create after a '--' like this:
+
+                  lxc-create --name=NAME [lxc-create-options] -- [template-options] [PKG...]
+
+               PKG  Additional APK package(s) to install into the container.
+
+               Template options:
+                  -a ARCH, --arch=ARCH   The container architecture (e.g. x86, x86_64); defaults
+                                         to the host arch.
+                  -d, --debug            Run this script in a debug mode (set -x and wget w/o -q).
+                  -F, --flush-cache      Remove cached files before build.
+                  -m URL --mirror=URL    The Alpine mirror to use; defaults to random mirror.
+                  -r VER, --release=VER  The Alpine release branch to install; default is the
+                                         latest stable.
+
+               Environment variables:
+                  APK             The apk-tools binary to use when building rootfs. If not set
+                                  or not executable and apk is not on PATH, then the script
+                                  will download the latest apk-tools-static.
+                  APK_KEYS_DIR    Path to directory with GPG keys for APK. If not set and
+                                  /etc/apk/keys does not contain alpine keys, then the script
+                                  will download the keys from ${APK_KEYS_URI}.
+                  LXC_CACHE_PATH  Path to the cache directory where to store bootstrap files
+                                  and APK packages.
+       EOF
 }
 
-install_alpine() {
-    rootfs="$1"
-    shift
-    mkdir -p "$rootfs"/etc/apk || return 1
-    : ${keys_dir:=/etc/apk/keys}
-    if ! [ -d "$rootfs"/etc/apk/keys ] && [ -d "$keys_dir" ]; then
-        cp -r "$keys_dir" "$rootfs"/etc/apk/keys
-    fi
-    if [ -n "$repository" ]; then
-        echo "$repository" > "$rootfs"/etc/apk/repositories
-    else
-        cp /etc/apk/repositories "$rootfs"/etc/apk/repositories || return 1
-        if [ -n "$release" ]; then
-            sed -E -i "s:/[^/]+/([^/]+)$:/$release/\\1:" \
-                "$rootfs"/etc/apk/repositories
-        fi
-    fi
-    opt_arch=
-    if [ -n "$apk_arch" ]; then
-        opt_arch="--arch $apk_arch"
-    fi
-    $APK add -U --initdb --root $rootfs $opt_arch "$@" alpine-base
+die() {
+       local retval=$1; shift
+
+       printf 'ERROR: %s\n' "$@" 1>&2
+       exit $retval
 }
 
-configure_alpine() {
-    rootfs="$1"
-    echo "Setting up /etc/inittab"
-    cat >"$rootfs"/etc/inittab<<EOF
-::sysinit:/sbin/rc sysinit
-::wait:/sbin/rc default
-console:12345:respawn:/sbin/getty 38400 console
-tty1:12345:respawn:/sbin/getty 38400 tty1
-tty2:12345:respawn:/sbin/getty 38400 tty2
-tty3:12345:respawn:/sbin/getty 38400 tty3
-tty4:12345:respawn:/sbin/getty 38400 tty4
-::ctrlaltdel:/sbin/reboot
-::shutdown:/sbin/rc shutdown
-EOF
-    # set up timezone
-    if [ -f /etc/TZ ]; then
-        cp /etc/TZ "$rootfs/etc/TZ"
-    fi
+einfo() {
+       printf "\n==> $1\n"
+}
 
-    # set up nameserver
-    grep nameserver /etc/resolv.conf > "$rootfs/etc/resolv.conf"
+fetch() {
+       if [ "$DEBUG" = 'yes' ]; then
+               wget -T 10 -O - $@
+       else
+               wget -T 10 -O - -q $@
+       fi
+}
 
-    # configure the network using the dhcp
-    cat <<EOF > $rootfs/etc/network/interfaces
-auto lo
-iface lo inet loopback
+latest_release_branch() {
+       local arch="$1"
+       local branch=$(fetch "$MIRROR_URL/latest-stable/releases/$arch/latest-releases.yaml" \
+               | sed -En 's/^[ \t]*branch: (.*)$/\1/p' \
+               | head -n 1)
+       [ -n "$branch" ] && echo "$branch"
+}
 
-auto eth0
-iface eth0 inet dhcp
-EOF
+parse_arch() {
+       case "$1" in
+               x86 | i[3-6]86) echo 'x86';;
+               x86_64 | amd64) echo 'x86_64';;
+               arm*) echo 'armhf';;
+               *) return 1;;
+       esac
+}
 
-    # set the hostname
-    echo $hostname > $rootfs/etc/hostname
-
-    # missing device nodes
-    echo "Setting up device nodes"
-    mkdir -p -m 755 "$rootfs/dev/pts"
-    mkdir -p -m 1777 "$rootfs/dev/shm"
-    mknod -m 666 "$rootfs/dev/zero" c 1 5
-    mknod -m 666 "$rootfs/dev/full" c 1 7
-    mknod -m 666 "$rootfs/dev/random" c 1 8
-    mknod -m 666 "$rootfs/dev/urandom" c 1 9
-    mknod -m 666 "$rootfs/dev/tty0" c 4 0
-    mknod -m 666 "$rootfs/dev/tty1" c 4 1
-    mknod -m 666 "$rootfs/dev/tty2" c 4 2
-    mknod -m 666 "$rootfs/dev/tty3" c 4 3
-    mknod -m 666 "$rootfs/dev/tty4" c 4 4
-#    mknod -m 600 "$rootfs/dev/initctl" p
-    mknod -m 666 "$rootfs/dev/tty" c 5 0
-    mknod -m 666 "$rootfs/dev/console" c 5 1
-    mknod -m 666 "$rootfs/dev/ptmx" c 5 2
-
-    # start services
-    ln -s /etc/init.d/bootmisc "$rootfs"/etc/runlevels/boot/bootmisc
-    ln -s /etc/init.d/syslog "$rootfs"/etc/runlevels/boot/syslog
-
-    return 0
+random_mirror_url() {
+       local url=$(fetch "$MIRRORS_LIST_URL" | shuf -n 1)
+       [ -n "$url" ] && echo "$url"
 }
 
-copy_configuration() {
-    path=$1
-    rootfs=$2
-    hostname=$3
-
-    grep -q "^lxc.rootfs" $path/config 2>/dev/null \
-        || echo "lxc.rootfs = $rootfs" >> $path/config
-    if [ -n "$lxc_arch" ]; then
-        echo "lxc.arch = $lxc_arch" >> $path/config
-    fi
-
-    lxc_network_link_line="# lxc.network.link = br0"
-    for br in lxcbr0 virbr0 br0; do
-        if [ -d /sys/class/net/$br/bridge ]; then
-            lxc_network_link_line="lxc.network.link = $br"
-            break
-        fi
-    done
-
-    if ! grep -q "^lxc.network.type" $path/config 2>/dev/null; then
-        cat <<EOF >> $path/config
-lxc.network.type = veth
-$lxc_network_link_line
-lxc.network.flags = up
-EOF
-    fi
-
-    # if there is exactly one veth or macvlan network entry, make sure
-    # it has an associated mac address.
-    nics=$(awk -F '[ \t]*=[ \t]*' \
-        '$1=="lxc.network.type" && ($2=="veth" || $2=="macvlan") {print $2}' \
-        $path/config | wc -l)
-    if [ "$nics" -eq 1 ] && ! grep -q "^lxc.network.hwaddr" $path/config; then
-        # see http://sourceforge.net/tracker/?func=detail&aid=3411497&group_id=163076&atid=826303
-        hwaddr="fe:$(dd if=/dev/urandom bs=8 count=1 2>/dev/null |od -t x8 | \
-                      head -n 1 |awk '{print $2}' | cut -c1-10 |\
-                      sed 's/\(..\)/\1:/g; s/.$//')"
-        echo "lxc.network.hwaddr = $hwaddr" >> $path/config
-    fi
-
-    cat <<EOF >> $path/config
-
-lxc.tty = 4
-lxc.pts = 1024
-lxc.utsname = $hostname
-lxc.cap.drop = sys_module mac_admin mac_override sys_time sys_admin
-
-# When using LXC with apparmor, uncomment the next line to run unconfined:
-#lxc.aa_profile = unconfined
-
-# devices
-lxc.cgroup.devices.deny = a
-# /dev/null, zero and full
-lxc.cgroup.devices.allow = c 1:3 rwm
-lxc.cgroup.devices.allow = c 1:5 rwm
-lxc.cgroup.devices.allow = c 1:7 rwm
-# consoles
-lxc.cgroup.devices.allow = c 5:1 rwm
-lxc.cgroup.devices.allow = c 5:0 rwm
-lxc.cgroup.devices.allow = c 4:0 rwm
-lxc.cgroup.devices.allow = c 4:1 rwm
-# /dev/{,u}random
-lxc.cgroup.devices.allow = c 1:9 rwm
-lxc.cgroup.devices.allow = c 1:8 rwm
-lxc.cgroup.devices.allow = c 136:* rwm
-lxc.cgroup.devices.allow = c 5:2 rwm
-# rtc
-lxc.cgroup.devices.allow = c 254:0 rm
-
-# mounts point
-lxc.mount.auto=cgroup:mixed proc:mixed sys:mixed
-lxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0
-lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0
+run_exclusively() {
+       local lock_name="$1"
+       local timeout=$2
+       shift 2
 
-EOF
+       mkdir -p "$LOCAL_STATE_DIR/lock/subsys"
+
+       local retval
+       {
+               echo -n "Obtaining an exclusive lock..."
+               if ! flock -x 9; then
+                       echo ' failed.'
+                       return 1
+               fi
+               echo ' done'
+
+               "$@"; retval=$?
+       } 9> "$LOCAL_STATE_DIR/lock/subsys/lxc-alpine-$lock_name"
 
-    return 0
+       return $retval
 }
 
-die() {
-    echo "$@" >&2
-    exit 1
+
+#============================  Bootstrap  ===========================#
+
+bootstrap() {
+       if [ "$FLUSH_CACHE" = 'yes' ] && [ -d "$LXC_CACHE_DIR/bootstrap" ]; then
+               einfo 'Cleaning cached bootstrap files'
+               rm -Rf "$LXC_CACHE_DIR/bootstrap"
+       fi
+
+       einfo 'Fetching and/or verifying APK keys'
+       fetch_apk_keys "$APK_KEYS_DIR"
+
+       if [ ! -x "$APK" ]; then
+               einfo 'Fetching apk-tools static binary'
+
+               local host_arch=$(parse_arch $(uname -m))
+               fetch_apk_static "$LXC_CACHE_DIR/bootstrap" "$host_arch"
+       fi
 }
 
-usage() {
-    cat >&2 <<EOF
-Usage: $(basename $0) [-h|--help] [-r|--repository <url>]
-                   [-R|--release <release>] [-a|--arch <arch>]
-                   [--rootfs <rootfs>] -p|--path <path> -n|--name <name>
-                   [PKG...]
+fetch_apk_keys() {
+       local dest="$1"
+       local line keyname
+
+       mkdir -p "$dest"
+       cd "$dest"
+
+       echo "$APK_KEYS_SHA256" | while read -r line; do
+               keyname="${line##* }"
+               if [ ! -f "$keyname" ]; then
+                       fetch "$APK_KEYS_URI/$keyname" > "$keyname"
+               fi
+               echo "$line" | sha256sum -c -
+       done || exit 2
+
+       cd - >/dev/null
+}
+
+fetch_apk_static() {
+       local dest="$1"
+       local arch="$2"
+       local pkg_name='apk-tools-static'
+
+       mkdir -p "$dest"
+
+       local pkg_ver=$(fetch "$MIRROR_URL/latest-stable/main/$arch/APKINDEX.tar.gz" \
+               | tar -xzO APKINDEX \
+               | sed -n "/P:${pkg_name}/,/^$/ s/V:\(.*\)$/\1/p")
+
+       [ -n "$pkg_ver" ] || die 2 "Cannot find a version of $pkg_name in APKINDEX"
+
+       fetch "$MIRROR_URL/latest-stable/main/$arch/${pkg_name}-${pkg_ver}.apk" \
+               | tar -xz -C "$dest" sbin/  # --extract --gzip --directory
+
+       [ -f "$dest/sbin/apk.static" ] || die 2 'apk.static not found'
+
+       local keyname=$(echo "$dest"/sbin/apk.static.*.pub | sed 's/.*\.SIGN\.RSA\.//')
+       openssl dgst -sha1 \
+               -verify "$APK_KEYS_DIR/$keyname" \
+               -signature "$dest/sbin/apk.static.SIGN.RSA.$keyname" \
+               "$dest/sbin/apk.static" \
+               || die 2 'Signature verification for apk.static failed'
+
+       # Note: apk doesn't return 0 for --version
+       local out="$("$dest"/sbin/apk.static --version)"
+       echo "$out"
+
+       [ "${out%% *}" = 'apk-tools' ] || die 3 'apk.static --version failed'
+}
+
+
+#============================  Install  ============================#
+
+install() {
+       local dest="$1"
+       local arch="$2"
+       local branch="$3"
+       local extra_packages="$4"
+       local apk_cache="$LXC_CACHE_DIR/apk/$arch"
+       local repo_url="$MIRROR_URL/$branch/main"
+
+       if [ "$FLUSH_CACHE" = 'yes' ] && [ -d "$apk_cache" ]; then
+               einfo "Cleaning cached APK packages for $arch"
+               rm -Rf "$apk_cache"
+       fi
+       mkdir -p "$apk_cache"
+
+       einfo "Installing Alpine Linux in $dest"
+       cd "$dest"
+
+       mkdir -p etc/apk
+       ln -s "$apk_cache" etc/apk/cache
+       echo "$repo_url" > etc/apk/repositories
+
+       install_packages "$arch" alpine-base $extra_packages
+       make_dev_nodes
+       setup_inittab
+       setup_hosts
+       setup_network
+       setup_services
+
+       chroot . /bin/true \
+               || die 3 'Failed to execute /bin/true in chroot, the builded rootfs is broken!'
+
+       rm etc/apk/cache
+       cd - >/dev/null
+}
+
+install_packages() {
+       local arch="$1"; shift
+       local packages="$@"
+
+       $APK --arch="$arch" --root=. --keys-dir="$APK_KEYS_DIR" \
+               --update-cache --initdb add $packages
+}
+
+make_dev_nodes() {
+       mkdir -p -m 755 dev/pts
+       mkdir -p -m 1777 dev/shm
+
+       mknod -m 666 dev/zero c 1 5
+       mknod -m 666 dev/full c 1 7
+       mknod -m 666 dev/random c 1 8
+       mknod -m 666 dev/urandom c 1 9
+
+       local i; for i in $(seq 0 4); do
+               mknod -m 620 dev/tty$i c 4 $i
+               chown 0:5 dev/tty$i  # root:tty
+       done
+
+       mknod -m 666 dev/tty c 5 0
+       chown 0:5 dev/tty  # root:tty
+       mknod -m 620 dev/console c 5 1
+       mknod -m 666 dev/ptmx c 5 2
+       chown 0:5 dev/ptmx  # root:tty
+}
+
+setup_inittab() {
+       # Remove unwanted ttys.
+       sed -i '/^tty[5-9]\:\:.*$/d' etc/inittab
+
+       cat <<-EOF >> etc/inittab
+               # Main LXC console console
+               ::respawn:/sbin/getty 38400 console
+       EOF
+}
+
+setup_hosts() {
+       # This runscript injects localhost entries with the current hostname
+       # into /etc/hosts.
+       cat <<'EOF' > etc/init.d/hosts
+#!/sbin/openrc-run
+
+start() {
+       local start_tag='# begin generated'
+       local end_tag='# end generated'
+
+       local content=$(
+               cat <<-EOF
+                       $start_tag by /etc/init.d/hosts
+                       127.0.0.1  $(hostname).local $(hostname) localhost
+                       ::1        $(hostname).local $(hostname) localhost
+                       $end_tag
+               EOF
+       )
+
+       if grep -q "^${start_tag}" /etc/hosts; then
+               # escape \n, busybox sed doesn't like them
+               content=${content//$'\n'/\\$'\n'}
+
+               sed -ni "/^${start_tag}/ {
+                               a\\${content}
+                               # read and discard next line and repeat until $end_tag or EOF
+                               :a; n; /^${end_tag}/!ba; n
+                       }; p" /etc/hosts
+       else
+               printf "$content" >> /etc/hosts
+       fi
+}
 EOF
+       chmod +x etc/init.d/hosts
+
+       # Wipe it, will be generated by the above runscript.
+       echo -n > etc/hosts
 }
 
-usage_err() {
-    usage
-    exit 1
+setup_network() {
+       # Note: loopback is automatically started by LXC.
+       cat <<-EOF > etc/network/interfaces
+               auto eth0
+               iface eth0 inet dhcp
+       EOF
 }
 
-default_path=@LXCPATH@
-release=
-arch=$(uname -m)
+setup_services() {
+       local svc_name
+
+       # Specify the LXC subsystem.
+       sed -i 's/^#*rc_sys=.*/rc_sys="lxc"/' etc/rc.conf
 
-# template mknods, requires root
-if [ $(id -u) -ne 0 ]; then
-   echo "$(basename $0): must be run as root" >&2
-   exit 1
+       # boot runlevel
+       for svc_name in bootmisc hosts syslog; do
+               ln -s /etc/init.d/$svc_name etc/runlevels/boot/$svc_name
+       done
+
+       # default runlevel
+       for svc_name in networking cron; do
+               ln -s /etc/init.d/$svc_name etc/runlevels/default/$svc_name
+       done
+}
+
+
+#===========================  Configure  ===========================#
+
+configure_container() {
+       local config="$1"
+       local hostname="$2"
+       local arch="$3"
+
+       cat <<-EOF >> "$config"
+
+               # Specify container architecture.
+               lxc.arch = $arch
+
+               # Set hostname.
+               lxc.utsname = $hostname
+
+               # If something doesn't work, try to comment this out.
+               # Dropping sys_admin disables container root from doing a lot of things
+               # that could be bad like re-mounting lxc fstab entries rw for example,
+               # but also disables some useful things like being able to nfs mount, and
+               # things that are already namespaced with ns_capable() kernel checks, like
+               # hostname(1).
+               lxc.cap.drop = sys_admin
+
+               # Include common configuration.
+               lxc.include = $LXC_TEMPLATE_CONFIG/alpine.common.conf
+       EOF
+}
+
+
+#=============================  Main  ==============================#
+
+if [ "$(id -u)" != "0" ]; then
+       die 1 "This script must be run as 'root'"
 fi
 
-options=$(getopt -o hn:p:r:R:a: -l help,name:,rootfs:,path:,repository:,release:,arch: -- "$@")
-[ $? -eq 0 ] || usage_err
+# Parse command options.
+options=$(getopt -o a:dFm:n:p:r:h -l arch:,debug,flush-cache,mirror:,name:,\
+path:,release:,rootfs:,help,mapped-uid:,mapped-gid: -- "$@")
 eval set -- "$options"
 
+# Clean variables and set defaults.
+arch="$(uname -m)"
+debug='no'
+flush_cache='no'
+mirror_url=
+name=
+path=
+release=
+rootfs=
+
+# Process command options.
 while [ $# -gt 0 ]; do
-    case "$1" in
-    -h|--help)
-        usage
-        exit 0
-        ;;
-    -n|--name)
-        name=$2
-        ;;
-    --rootfs)
-        rootfs=$2
-        ;;
-    -p|--path)
-        path=$2
-        ;;
-    -r|--repository)
-        repository=$2
-       ;;
-    -R|--release)
-        release=$2
-        ;;
-    -a|--arch)
-        arch=$2
-        ;;
-    --)
-       shift
-        break;;
-    esac
-    shift 2
+       case $1 in
+               -a | --arch)
+                       arch=$2; shift 2
+               ;;
+               -d | --debug)
+                       debug='yes'; shift 1
+               ;;
+               -F | --flush-cache)
+                       flush_cache='yes'; shift 1
+               ;;
+               -m | --mirror)
+                       mirror_url=$2; shift 2
+               ;;
+               -n | --name)
+                       name=$2; shift 2
+               ;;
+               -p | --path)
+                       path=$2; shift 2
+               ;;
+               -r | --release)
+                       release=$2; shift 2
+               ;;
+               --rootfs)
+                       rootfs=$2; shift 2
+               ;;
+               -h | --help)
+                       usage; exit 0
+               ;;
+               --)
+                       shift; break
+               ;;
+               --mapped-[ug]id)
+                       die 1 "This template can't be used for unprivileged containers." \
+                               'You may want to try the "download" template instead.'
+               ;;
+               *)
+                       echo "Unknown option: $1" 1>&2
+                       usage; exit 1
+               ;;
+       esac
 done
 
+extra_packages="$@"
 
-[ -z "$name" ] && usage_err
+[ "$debug" = 'yes' ] && set -x
 
-if [ -z "${path}" ]; then
-    path="${default_path}/${name}"
-fi
+# Set global variables.
+readonly DEBUG="$debug"
+readonly FLUSH_CACHE="$flush_cache"
+readonly MIRROR_URL="${mirror_url:-$(random_mirror_url)}"
+
+# Validate options.
+[ -n "$name" ] || die 1 'Missing required option --name'
+[ -n "$path" ] || die 1 'Missing required option --path'
 
+if [ -z "$rootfs" ] && [ -f "$path/config" ]; then
+       rootfs="$(sed -nE 's/^lxc.rootfs\s*=\s*(.*)$/\1/p' "$path/config")"
+fi
 if [ -z "$rootfs" ]; then
-    rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 2>/dev/null`
-    if [ -z "$rootfs" ]; then
-        rootfs="${path}/rootfs"
-    fi
+       rootfs="$path/rootfs"
 fi
 
-lxc_arch=$arch
-apk_arch=$arch
-
-case "$arch" in
-    i[3-6]86)
-        apk_arch=x86
-        lxc_arch=x86
-        ;;
-    x86)
-        lxc_arch=i686
-        ;;
-    x86_64|"")
-        ;;
-    arm*)
-        apk_arch=armhf
-        ;;
-    *)
-        die "unsupported architecture: $arch"
-        ;;
-esac
-
-: ${APK:=apk}
-if ! which $APK >/dev/null; then
-    get_static_apk "$rootfs" || die "Failed to download a valid static apk"
+arch=$(parse_arch "$arch") \
+       || die 1 "Unsupported architecture: $arch"
+
+if [ -z "$release" ]; then
+       release=$(latest_release_branch "$arch") \
+               || die 2 'Failed to resolve Alpine last release branch'
 fi
 
-install_alpine "$rootfs" "$@" || die "Failed to install rootfs for $name"
-configure_alpine "$rootfs" "$name" || die "Failed to configure $name"
-copy_configuration "$path" "$rootfs" "$name"
+# Here we go!
+run_exclusively 'bootstrap' 10 bootstrap
+run_exclusively "$arch" 30 install "$rootfs" "$arch" "$release" "$extra_packages"
+configure_container "$path/config" "$name" "$arch"
+
+einfo "Container's rootfs and config have been created"
+cat <<-EOF
+       Edit the config file $path/config to check/enable networking setup.
+       The installed system is preconfigured for a loopback and single network
+       interface configured via DHCP.
+
+       To start the container, run "lxc-start -n $name".
+       The root password is not set; to enter the container run "lxc-attach -n $name".
+EOF
index 8b4168c..57c6274 100644 (file)
@@ -57,33 +57,33 @@ configure_altlinux()
     mkdir -p $rootfs_path/selinux
     echo 0 > $rootfs_path/selinux/enforce
 
-    mkdir -p ${rootfs_path}/etc/net/ifaces/veth0
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/options
+    mkdir -p ${rootfs_path}/etc/net/ifaces/eth0
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/options
 BOOTPROTO=${BOOTPROTO}
 ONBOOT=yes
-NM_CONTROLLED=no
+NM_CONTROLLED=yes
 TYPE=eth
 EOF
 
 if [ ${BOOTPROTO} != "dhcp" ]; then
     # ip address
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/ipv4address
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/ipv4address
 ${ipv4}
 EOF
 
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/ipv4route
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/ipv4route
 ${gw}
 EOF
 
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/resolv.conf
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/resolv.conf
 nameserver ${dns}
 EOF
 
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/ipv6address
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/ipv6address
 ${ipv6}
 EOF
 
-    cat <<EOF > ${rootfs_path}/etc/net/ifaces/veth0/ipv6route
+    cat <<EOF > ${rootfs_path}/etc/net/ifaces/eth0/ipv6route
 ${gw6}
 EOF
 
@@ -109,14 +109,17 @@ EOF
     echo "console" >> ${rootfs_path}/etc/securetty
 
     # Enable services
-    for service in network syslogd random
+    for service in network syslogd random NetworkManager
     do
        chroot ${rootfs_path} chkconfig $service --list &>/dev/null && chroot ${rootfs_path} chkconfig $service on || true
+       # For systemd
+       chroot ${rootfs_path} systemctl -q enable $service &>/dev/null|| true
     done
     # Disable services
     for service in rawdevices fbsetfont
     do
        chroot ${rootfs_path} chkconfig $service --list &>/dev/null && chroot ${rootfs_path} chkconfig $service off || true
+       chroot ${rootfs_path} systemctl -q disable $service &>/dev/null || true
     done
 
     subst 's/^\([3-9]\+:[0-9]\+:respawn:\/sbin\/mingetty.*\)/#\1/' ${rootfs_path}/etc/inittab
@@ -175,7 +178,7 @@ download_altlinux()
     APT_GET="apt-get -o RPM::RootDir=$INSTALL_ROOT -y"
     PKG_LIST="$(grep -hs '^[^#]' "$profile_dir/$profile")"
     # if no configuration file $profile -- fall back to default list of packages
-    [ -z "$PKG_LIST" ] && PKG_LIST="interactivesystem apt apt-conf-sisyphus etcnet openssh-server systemd systemd-units systemd-sysvinit"
+    [ -z "$PKG_LIST" ] && PKG_LIST="interactivesystem apt apt-conf-sisyphus etcnet-full openssh-server systemd-sysvinit systemd-units systemd NetworkManager-daemon"
 
     mkdir -p $INSTALL_ROOT/var/lib/rpm
     rpm --root $INSTALL_ROOT  --initdb
@@ -272,11 +275,11 @@ lxc.cap.drop = sys_module mac_admin mac_override sys_time
 #lxc.aa_profile = unconfined
 
 #networking
-lxc.network.type = $lxc_network_type
-lxc.network.flags = up
-lxc.network.link = $lxc_network_link
-lxc.network.name = veth0
-lxc.network.mtu = 1500
+#lxc.network.type = $lxc_network_type
+#lxc.network.flags = up
+#lxc.network.link = $lxc_network_link
+#lxc.network.name = veth0
+#lxc.network.mtu = 1500
 EOF
 if [ ! -z ${ipv4} ]; then
     cat <<EOF >> $config_path/config
index c692abf..8aa1d8d 100644 (file)
@@ -198,7 +198,7 @@ Mandatory args:
   -n,--name           container name, used to as an identifier for that container from now on
 Optional args:
   -p,--path           path to where the container rootfs will be created (${default_path})
-  --rootfs            path for actual container rootfs, (${default_path/rootfs)
+  --rootfs            path for actual container rootfs, (${default_path}/rootfs)
   -P,--packages       preinstall additional packages, comma-separated list
   -e,--enable_units   enable systemd services, comma-separated list
   -d,--disable_units  disable systemd services, comma-separated list
index 72531d6..336fa12 100644 (file)
@@ -22,6 +22,7 @@
 
 LXC_MAPPED_UID=
 LXC_MAPPED_GID=
+SSH=
 
 # Make sure the usual locations are in PATH
 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
@@ -37,6 +38,31 @@ am_in_userns() {
 in_userns=0
 [ $(am_in_userns) = "yes" ] && in_userns=1
 
+copy_binary()
+{
+    binary_path=`which $1`
+    if [ $? -ne 0 ]; then
+        echo "Unable to find $1 binary on the system"
+        return 1
+    fi
+
+    dir_path="${binary_path%/*}"
+    echo /{,usr/}{,s}bin | grep $dir_path >/dev/null 2>&1
+    if [ $? -ne 0 ]; then
+        echo "Binary $1 is located at $binary_path and will not be copied"
+        echo "($dir_path not supported)"
+        return 1
+    fi
+
+    cp $binary_path $rootfs/$binary_path
+    if [ $? -ne 0 ]; then
+        echo "Failed to copy $binary_path to rootfs"
+        return 1
+    fi
+
+    return 0
+}
+
 install_busybox()
 {
     rootfs=$1
@@ -160,6 +186,113 @@ EOF
     return $res
 }
 
+install_dropbear()
+{
+    # copy dropbear binary
+    copy_binary dropbear || return 1
+
+    # make symlinks to various ssh utilities
+    utils="\
+        $rootfs/usr/bin/dbclient \
+        $rootfs/usr/bin/scp \
+        $rootfs/usr/bin/ssh \
+        $rootfs/usr/sbin/dropbearkey \
+        $rootfs/usr/sbin/dropbearconvert \
+    "
+    echo $utils | xargs -n1 ln -s /usr/sbin/dropbear
+
+    # add necessary config files
+    mkdir $rootfs/etc/dropbear
+    dropbearkey -t rsa -f $rootfs/etc/dropbear/dropbear_rsa_host_key > /dev/null 2>&1
+    dropbearkey -t dss -f $rootfs/etc/dropbear/dropbear_dss_host_key > /dev/null 2>&1
+
+    echo "'dropbear' ssh utility installed"
+
+    return 0
+}
+
+install_openssh()
+{
+    # tools to be installed
+    server_utils="sshd"
+    client_utils="\
+        ssh \
+        scp \
+        "
+    client_optional_utils="\
+        sftp \
+        ssh-add \
+        ssh-agent \
+        ssh-keygen \
+        ssh-keyscan \
+        ssh-argv0 \
+        ssh-copy-id \
+        "
+
+    # new folders used by ssh
+    ssh_tree="\
+$rootfs/etc/ssh \
+$rootfs/var/empty/sshd \
+$rootfs/var/lib/empty/sshd \
+$rootfs/var/run/sshd \
+"
+
+    # create folder structure
+    mkdir -p $ssh_tree
+    if [ $? -ne 0 ]; then
+        return 1
+    fi
+
+    # copy binaries
+    for bin in $server_utils $client_utils; do
+        copy_binary $bin || return 1
+    done
+
+    for bin in $client_optional_utils; do
+        tool_path=`which $bin` && copy_binary $bin
+    done
+
+    # add user and group
+    cat <<EOF >> $rootfs/etc/passwd
+sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
+EOF
+
+    cat <<EOF >> $rootfs/etc/group
+sshd:x:74:
+EOF
+
+    # generate container keys
+    ssh-keygen -t rsa -N "" -f $rootfs/etc/ssh/ssh_host_rsa_key >/dev/null 2>&1
+    ssh-keygen -t dsa -N "" -f $rootfs/etc/ssh/ssh_host_dsa_key >/dev/null 2>&1
+
+    # by default setup root password with no password
+    cat <<EOF > $rootfs/etc/ssh/sshd_config
+Port 22
+Protocol 2
+HostKey /etc/ssh/ssh_host_rsa_key
+HostKey /etc/ssh/ssh_host_dsa_key
+UsePrivilegeSeparation yes
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+SyslogFacility AUTH
+LogLevel INFO
+LoginGraceTime 120
+PermitRootLogin yes
+StrictModes yes
+RSAAuthentication yes
+PubkeyAuthentication yes
+IgnoreRhosts yes
+RhostsRSAAuthentication no
+HostbasedAuthentication no
+PermitEmptyPasswords yes
+ChallengeResponseAuthentication no
+EOF
+
+    echo "'OpenSSH' utility installed"
+
+    return 0
+}
+
 configure_busybox()
 {
     rootfs=$1
@@ -171,13 +304,6 @@ configure_busybox()
         return 1
     fi
 
-    file -L $(which busybox) | grep -q "statically linked"
-    if [ $? -ne 0 ]; then
-        echo "warning : busybox is not statically linked."
-        echo "warning : The template script may not correctly"
-        echo "warning : setup the container environment."
-    fi
-
     # copy busybox in the rootfs
     cp $(which busybox) $rootfs/bin
     if [ $? -ne 0 ]; then
@@ -197,6 +323,9 @@ configure_busybox()
     # relink /sbin/init
     ln $rootfs/bin/busybox $rootfs/sbin/init
 
+    # /etc/fstab must exist for "mount -a"
+    touch $rootfs/etc/fstab
+
     # passwd exec must be setuid
     chmod +s $rootfs/bin/passwd
     touch $rootfs/etc/shadow
@@ -230,34 +359,6 @@ EOF
     lxc-unshare -s MOUNT -- /bin/sh < $CHPASSWD_FILE
     rm $CHPASSWD_FILE
 
-    # add ssh functionality if dropbear package available on host
-    which dropbear >/dev/null 2>&1
-    if [ $? -eq 0 ]; then
-        # copy dropbear binary
-        cp $(which dropbear) $rootfs/usr/sbin
-        if [ $? -ne 0 ]; then
-            echo "Failed to copy dropbear in the rootfs"
-            return 1
-        fi
-
-        # make symlinks to various ssh utilities
-        utils="\
-            $rootfs/usr/bin/dbclient \
-            $rootfs/usr/bin/scp \
-            $rootfs/usr/bin/ssh \
-            $rootfs/usr/sbin/dropbearkey \
-            $rootfs/usr/sbin/dropbearconvert \
-        "
-        echo $utils | xargs -n1 ln -s /usr/sbin/dropbear
-
-        # add necessary config files
-        mkdir $rootfs/etc/dropbear
-        dropbearkey -t rsa -f $rootfs/etc/dropbear/dropbear_rsa_host_key > /dev/null 2>&1
-        dropbearkey -t dss -f $rootfs/etc/dropbear/dropbear_dss_host_key > /dev/null 2>&1
-
-        echo "'dropbear' ssh utility installed"
-    fi
-
     return 0
 }
 
@@ -270,6 +371,7 @@ copy_configuration()
 grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
 cat <<EOF >> $path/config
 lxc.haltsignal = SIGUSR1
+lxc.rebootsignal = SIGTERM
 lxc.utsname = $name
 lxc.tty = 1
 lxc.pts = 1
@@ -314,12 +416,12 @@ remap_userns()
 usage()
 {
     cat <<EOF
-$1 -h|--help -p|--path=<path>
+$1 -h|--help -p|--path=<path> -s|--ssh={dropbear,openssh}
 EOF
     return 0
 }
 
-options=$(getopt -o hp:n: -l help,rootfs:,path:,name:,mapped-uid:,mapped-gid: -- "$@")
+options=$(getopt -o hp:n:s: -l help,rootfs:,path:,name:,mapped-uid:,mapped-gid:,ssh: -- "$@")
 if [ $? -ne 0 ]; then
     usage $(basename $0)
     exit 1
@@ -335,6 +437,7 @@ do
         -n|--name)      name=$2; shift 2;;
         --mapped-uid)   LXC_MAPPED_UID=$2; shift 2;;
         --mapped-gid)   LXC_MAPPED_GID=$2; shift 2;;
+        -s|--ssh)       SSH=$2; shift 2;;
         --)             shift 1; break ;;
         *)              break ;;
     esac
@@ -383,3 +486,28 @@ if [ $? -ne 0 ]; then
     echo "failed to remap files to user"
     exit 1
 fi
+
+if [ -n "$SSH" ]; then
+    case "$SSH" in
+        "dropbear")
+            install_dropbear
+            if [ $? -ne 0 ]; then
+                echo "Unable to install 'dropbear' ssh utility"
+                exit 1
+            fi ;;
+        "openssh")
+            install_openssh
+            if [ $? -ne 0 ]; then
+                echo "Unable to install 'OpenSSH' utility"
+                exit 1
+            fi ;;
+        *)
+            echo "$SSH: unrecognized ssh utility"
+            exit 1
+    esac
+else
+    which dropbear >/dev/null 2>&1
+    if [ $? -eq 0 ]; then
+        install_dropbear
+    fi
+fi
index 1a27cd3..ef8061c 100644 (file)
@@ -249,7 +249,7 @@ configure_centos()
 DEVICE=eth0
 BOOTPROTO=dhcp
 ONBOOT=yes
-HOSTNAME=${UTSNAME}
+HOSTNAME=${utsname}
 NM_CONTROLLED=no
 TYPE=Ethernet
 MTU=${MTU}
@@ -259,7 +259,7 @@ EOF
     # set the hostname
     cat <<EOF > ${rootfs_path}/etc/sysconfig/network
 NETWORKING=yes
-HOSTNAME=${UTSNAME}
+HOSTNAME=${utsname}
 EOF
 
     # set minimal hosts
@@ -763,7 +763,8 @@ then
     fi
 fi
 
-cache_base=@LOCALSTATEDIR@/cache/lxc/centos/$basearch
+# Allow the cache base to be set by environment variable
+cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/centos/$basearch
 
 # Let's do something better for the initial root password.
 # It's not perfect but it will defeat common scanning brute force
@@ -915,7 +916,16 @@ then
 else
     if [ ${root_expire_password} = "yes" ]
     then
-        echo "
+        if ( mountpoint -q -- "${rootfs_path}" )
+        then
+            echo "To reset the root password, you can do:
+
+        lxc-start -n ${name}
+        lxc-attach -n ${name} -- passwd
+        lxc-stop -n ${name}
+"
+        else
+           echo "
 The root password is set up as "expired" and will require it to be changed
 at first login, which you should do as soon as possible.  If you lose the
 root password or wish to change it without starting the container, you
@@ -924,5 +934,6 @@ also reset the expired flag):
 
         chroot ${rootfs_path} passwd
 "
+        fi
     fi
 fi
index 349cdbf..395416b 100644 (file)
@@ -58,10 +58,11 @@ am_in_userns() {
 in_userns=0
 [ $(am_in_userns) = "yes" ] && in_userns=1
 
+# Allow the cache base to be set by environment variable
 if [ $(id -u) -eq 0 ]; then
-    CACHE_D="@LOCALSTATEDIR@/cache/lxc/cirros"
+    CACHE_D=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc/cirros"}
 else
-    CACHE_D="$HOME/.cache/lxc/cirros"
+    CACHE_D=${LXC_CACHE_PATH:-"$HOME/.cache/lxc/cirros"}
 fi
 
 error() { echo "$@" 1>&2; }
@@ -129,8 +130,6 @@ lxc.cap.drop = sys_module mac_admin mac_override sys_time
 
 # When using LXC with apparmor, uncomment the next line to run unconfined:
 #lxc.aa_profile = unconfined
-# To support container nesting on an Ubuntu host, uncomment next two lines:
-#lxc.aa_profile = lxc-container-default-with-nesting
 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
 
 lxc.cgroup.devices.deny = a
index 54393ca..1ed6f20 100644 (file)
@@ -34,19 +34,22 @@ done
 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 export GREP_OPTIONS=""
 
-MIRROR=${MIRROR:-http://http.debian.net/debian}
+MIRROR=${MIRROR:-http://httpredir.debian.org/debian}
 SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/}
 LOCALSTATEDIR="@LOCALSTATEDIR@"
 LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
+# Allows the lxc-cache directory to be set by environment variable
+LXC_CACHE_PATH=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc"}
 
 configure_debian()
 {
     rootfs=$1
     hostname=$2
+    num_tty=$3
 
     # squeeze only has /dev/tty and /dev/tty0 by default,
     # therefore creating missing device nodes for tty1-4.
-    for tty in $(seq 1 4); do
+    for tty in $(seq 1 $num_tty); do
         if [ ! -e $rootfs/dev/tty$tty ]; then
             mknod $rootfs/dev/tty$tty c 4 $tty
         fi
@@ -66,10 +69,7 @@ l6:6:wait:/etc/init.d/rc 6
 # Normally not reached, but fallthrough in case of emergency.
 z6:6:respawn:/sbin/sulogin
 1:2345:respawn:/sbin/getty 38400 console
-c1:12345:respawn:/sbin/getty 38400 tty1 linux
-c2:12345:respawn:/sbin/getty 38400 tty2 linux
-c3:12345:respawn:/sbin/getty 38400 tty3 linux
-c4:12345:respawn:/sbin/getty 38400 tty4 linux
+$(for tty in $(seq 1 $num_tty); do echo "c${tty}:12345:respawn:/sbin/getty 38400 tty${tty} linux" ; done;)
 p6::ctrlaltdel:/sbin/init 6
 p0::powerfail:/sbin/init 0
 EOF
@@ -189,6 +189,8 @@ configure_debian_systemd()
 {
     path=$1
     rootfs=$2
+    config=$3
+    num_tty=$4
 
     # this only works if we have getty@.service to manipulate
     if [ -f ${rootfs}/lib/systemd/system/getty\@.service ]; then
@@ -204,7 +206,10 @@ configure_debian_systemd()
 
     # Fix getty-static-service as debootstrap does not install dbus
     if [ -e $rootfs//lib/systemd/system/getty-static.service ] ; then
-        sed 's/ getty@tty[5-9].service//g' $rootfs/lib/systemd/system/getty-static.service |  sed 's/\(tty2-tty\)[5-9]/\14/g' > $rootfs/etc/systemd/system/getty-static.service
+        local tty_services=$(for i in $(seq 2 $num_tty); do echo -n "getty@tty${i}.service "; done; )
+        sed 's/ getty@tty.*/'" $tty_services "'/g' \
+                $rootfs/lib/systemd/system/getty-static.service |  \
+                sed 's/\(tty2-tty\)[5-9]/\1'"${num_tty}"'/g' > $rootfs/etc/systemd/system/getty-static.service
     fi
 
     # This function has been copied and adapted from lxc-fedora
@@ -214,10 +219,16 @@ configure_debian_systemd()
     chroot ${rootfs} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
     # Make systemd honor SIGPWR
     chroot ${rootfs} ln -s /lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
-    # Setup getty service on the ttys we are going to allow in the
+    # Setup getty service on the ttys we are going to allow in the
     # default config.  Number should match lxc.tty
     ( cd ${rootfs}/etc/systemd/system/getty.target.wants
-        for i in 1 2 3 4 ; do ln -sf ../getty\@.service getty@tty${i}.service; done )
+        for i in $(seq 1 $num_tty) ; do ln -sf ../getty\@.service getty@tty${i}.service; done )
+
+    # Since we use static-getty.target; we need to mask container-getty@.service generated by
+    # container-getty-generator, so we don't get multiple instances of agetty running.
+    # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484
+    ( cd ${rootfs}/etc/systemd/system/getty.target.wants
+        for i in $(seq 0 $num_tty); do ln -sf /dev/null container-getty\@${i}.service; done )
 
     return 0
 }
@@ -246,6 +257,28 @@ openssh-server
     release=$3
 
     trap cleanup EXIT SIGHUP SIGINT SIGTERM
+
+    # Create the cache
+    mkdir -p "$cache"
+
+    # If debian-archive-keyring isn't installed, fetch GPG keys directly
+    releasekeyring=/usr/share/keyrings/debian-archive-keyring.gpg
+    if [ ! -f $releasekeyring ]; then
+        releasekeyring="$cache/archive-key.gpg"
+        case $release in
+            "squeeze")
+                gpgkeyname="archive-key-6.0"
+                ;;
+            "wheezy")
+                gpgkeyname="archive-key-7.0"
+                ;;
+            *)
+                gpgkeyname="archive-key-8"
+                ;;
+        esac
+        wget https://ftp-master.debian.org/keys/${gpgkeyname}.asc -O - --quiet \
+            | gpg --import --no-default-keyring --keyring=${releasekeyring}
+    fi
     # check the mini debian was not already downloaded
     mkdir -p "$cache/partial-$release-$arch"
     if [ $? -ne 0 ]; then
@@ -256,7 +289,7 @@ openssh-server
     # download a mini debian into a cache
     echo "Downloading debian minimal ..."
     debootstrap --verbose --variant=minbase --arch=$arch \
-        --include=$packages \
+        --include=$packages --keyring=${releasekeyring} \
         "$release" "$cache/partial-$release-$arch" $MIRROR
     if [ $? -ne 0 ]; then
         echo "Failed to download the rootfs, aborting."
@@ -289,10 +322,10 @@ copy_debian()
 
 install_debian()
 {
-    cache="$LOCALSTATEDIR/cache/lxc/debian"
     rootfs=$1
     release=$2
     arch=$3
+    cache="$4/debian"
     mkdir -p $LOCALSTATEDIR/lock/subsys/
     (
         flock -x 9
@@ -329,6 +362,7 @@ copy_configuration()
     rootfs=$2
     hostname=$3
     arch=$4
+    num_tty=$5
 
     # Generate the configuration file
     # if there is exactly one veth network entry, make sure it has an
@@ -354,6 +388,7 @@ copy_configuration()
     grep -q "^lxc.rootfs" $path/config 2> /dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
 
     cat <<EOF >> $path/config
+lxc.tty = $num_tty
 lxc.utsname = $hostname
 lxc.arch = $arch
 EOF
@@ -429,7 +464,7 @@ EOF
 
 clean()
 {
-    cache="$LOCALSTATEDIR/cache/lxc/debian"
+    cache=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc/debian"}
 
     if [ ! -e $cache ]; then
         exit 0
@@ -467,7 +502,7 @@ Options :
   -p, --path=PATH        directory where config and rootfs of this VM will be kept
   -a, --arch=ARCH        The container architecture. Can be one of: i686, x86_64,
                          amd64, armhf, armel, powerpc. Defaults to host arch.
-  -r, --release=RELEASE  Debian release. Can be one of: squeeze, wheezy, jessie, sid.
+  -r, --release=RELEASE  Debian release. Can be one of: wheezy, jessie, stretch, sid.
                          Defaults to current stable.
   --mirror=MIRROR        Debian mirror to use during installation. Overrides the MIRROR
                          environment variable (see below).
@@ -477,7 +512,7 @@ Options :
   --packages=PACKAGE_NAME1,PACKAGE_NAME2,...
                          List of additional packages to install. Comma separated, without space.
   -c, --clean            only clean up the cache and terminate
-  --main-only            include only Debian's main repository (i.e. no contrib and non-free).
+  --enable-non-free      include also Debian's contrib and non-free repositories.
 
 Environment variables:
 
@@ -490,7 +525,7 @@ EOF
     return 0
 }
 
-options=$(getopt -o hp:n:a:r:c -l arch:,clean,help,main-only,mirror:,name:,packages:,path:,release:,rootfs:,security-mirror: -- "$@")
+options=$(getopt -o hp:n:a:r:c -l arch:,clean,help,enable-non-free,mirror:,name:,packages:,path:,release:,rootfs:,security-mirror: -- "$@")
 if [ $? -ne 0 ]; then
         usage $(basename $0)
         exit 1
@@ -506,6 +541,7 @@ elif [ "$arch" = "armv7l" ]; then
     arch="armhf"
 fi
 hostarch=$arch
+mainonly=1
 
 while true
 do
@@ -515,7 +551,7 @@ do
 
         -a|--arch)            arch=$2; shift 2;;
         -c|--clean)           clean=1; shift 1;;
-           --main-only)       mainonly=1; shift 1;;
+           --enable-non-free) mainonly=0; shift 1;;
            --mirror)          MIRROR=$2; shift 2;;
         -n|--name)            name=$2; shift 2;;
            --packages)        packages=$2; shift 2;;
@@ -574,7 +610,7 @@ fi
 
 current_release=`wget ${MIRROR}/dists/stable/Release -O - 2> /dev/null | head |awk '/^Codename: (.*)$/ { print $2; }'`
 release=${release:-${current_release}}
-valid_releases=('squeeze' 'wheezy' 'jessie' 'stretch' 'sid')
+valid_releases=('wheezy' 'jessie' 'stretch' 'sid')
 if [[ ! "${valid_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]]; then
     echo "Invalid release ${release}, valid ones are: ${valid_releases[*]}"
     exit 1
@@ -584,31 +620,38 @@ fi
 config="$path/config"
 if [ -z "$rootfs" ]; then
     if grep -q '^lxc.rootfs' $config 2> /dev/null ; then
-        rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
+        rootfs=$(awk -F= '/^lxc.rootfs[ \t]+=/{ print $2 }' $config)
     else
         rootfs=$path/rootfs
     fi
 fi
 
-install_debian $rootfs $release $arch
+# determine the number of ttys - default is 4
+if grep -q '^lxc.tty' $config 2> /dev/null ; then
+    num_tty=$(awk -F= '/^lxc.tty[ \t]+=/{ print $2 }' $config)
+else
+    num_tty=4
+fi
+
+install_debian $rootfs $release $arch $LXC_CACHE_PATH
 if [ $? -ne 0 ]; then
     echo "failed to install debian"
     exit 1
 fi
 
-configure_debian $rootfs $name
+configure_debian $rootfs $name $num_tty
 if [ $? -ne 0 ]; then
     echo "failed to configure debian for a container"
     exit 1
 fi
 
-copy_configuration $path $rootfs $name $arch
+copy_configuration $path $rootfs $name $arch $num_tty
 if [ $? -ne 0 ]; then
     echo "failed write configuration file"
     exit 1
 fi
 
-configure_debian_systemd $path $rootfs
+configure_debian_systemd $path $rootfs $config $num_tty
 
 post_process ${rootfs} ${release} ${arch} ${hostarch} ${packages}
 
index e0a812f..d4cf830 100644 (file)
@@ -28,7 +28,7 @@ LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
 # Defaults
 DOWNLOAD_ARCH=
 DOWNLOAD_BUILD=
-DOWNLOAD_COMPAT_LEVEL=2
+DOWNLOAD_COMPAT_LEVEL=3
 DOWNLOAD_DIST=
 DOWNLOAD_FLUSH_CACHE="false"
 DOWNLOAD_FORCE_CACHE="false"
@@ -380,7 +380,9 @@ else
     LXC_CACHE_BASE="$HOME/.cache/lxc/"
 fi
 
-LXC_CACHE_PATH="$LXC_CACHE_BASE/download/$DOWNLOAD_DIST"
+# Allow the setting of the LXC_CACHE_PATH with the usage of environment variables.
+LXC_CACHE_PATH=${LXC_CACHE_PATH:-"$LXC_CACHE_BASE"}
+LXC_CACHE_PATH=$LXC_CACHE_PATH/download/$DOWNLOAD_DIST
 LXC_CACHE_PATH="$LXC_CACHE_PATH/$DOWNLOAD_RELEASE/$DOWNLOAD_ARCH/"
 LXC_CACHE_PATH="$LXC_CACHE_PATH/$DOWNLOAD_VARIANT"
 
index f6e5be5..a83a590 100644 (file)
@@ -570,8 +570,8 @@ but appears to be non-functional.  Skipping...  It should be removed.
 #       mount image to "squashfs"
 #       mount contained LiveOS to stage0
 
-# We're going to use the kernel.org mirror for the initial stages...
-#       1 - It's generally up to date and comnplete
+# We're going to use the archives.fedoraproject.org mirror for the initial stages...
+#       1 - It's generally up to date and complete
 #       2 - It's has high bandwidth access
 #       3 - It supports rsync and wildcarding (and we need both)
 #       4 - Not all the mirrors carry the LiveOS images
@@ -579,7 +579,7 @@ but appears to be non-functional.  Skipping...  It should be removed.
     if [[ ! -f ../LiveOS/squashfs.img ]]
     then
         echo "
-Downloading stage 0 LiveOS squashfs file system from mirrors.kernel.org...
+Downloading stage 0 LiveOS squashfs file system from archives.fedoraproject.org...
 Have a beer or a cup of coffee.  This will take a bit (~300MB).
 "
         sleep 3 # let him read it...
@@ -1282,7 +1282,8 @@ then
     fi
 fi
 
-cache_base=@LOCALSTATEDIR@/cache/lxc/fedora/$basearch
+# Allow the cache base to be set by environment variable
+cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/fedora/$basearch
 
 # Let's do something better for the initial root password.
 # It's not perfect but it will defeat common scanning brute force
@@ -1467,7 +1468,16 @@ then
 else
     if [ ${root_expire_password} = "yes" ]
     then
-        echo "
+        if ( mountpoint -q -- "${rootfs_path}" )
+        then
+            echo "To reset the root password, you can do:
+
+        lxc-start -n ${name}
+        lxc-attach -n ${name} -- passwd
+        lxc-stop -n ${name}
+"
+        else
+           echo "
 The root password is set up as "expired" and will require it to be changed
 at first login, which you should do as soon as possible.  If you lose the
 root password or wish to change it without starting the container, you
@@ -1476,5 +1486,6 @@ also reset the expired flag):
 
         chroot ${rootfs_path} passwd
 "
+        fi
     fi
 fi
index 0a76766..2ad16e8 100644 (file)
@@ -805,6 +805,7 @@ do
     -w|--password)         forced_password=1; password=$2; shift 2;;
     -s|--settings)         settings=$2; shift 2;;
     -m|--mirror)           mirror=$2; shift 2;;
+    --container-cache)  containercache=$2; shift 2;;
     --tty)                 [[ $2 -lt 6 ]] && tty=$2; shift 2;;
     --autologin)            autologin=1; shift 1;;
     --) shift 1; break ;;
@@ -812,7 +813,8 @@ do
     esac
 done
 
-cacheroot="@LOCALSTATEDIR@/cache/lxc/gentoo"
+# Allow the cache path to be set by environment variable
+cacheroot="${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/gentoo"
 portage_cache="${cacheroot}/portage.tbz"
 cachefs="${cacheroot}/rootfs-${arch}-${variant}"
 
index 6123c5e..12f9985 100644 (file)
@@ -42,7 +42,8 @@ export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 #Configurations
 #distro=cooker
 hostarch=$(uname -m)
-cache_base=@LOCALSTATEDIR@/cache/lxc/openmandriva/$arch
+# Allow the cache base to be set by environment variable
+cache_base="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/openmandriva/$arch}"
 default_path=@LXCPATH@
 default_profile=default
 root_password=root
index d4e2b28..6044d89 100644 (file)
@@ -136,8 +136,13 @@ download_opensuse()
     echo "Downloading opensuse minimal ..."
     mkdir -p "$cache/partial-$arch-packages"
     zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss/ repo-oss || return 1
-    zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update || return 1
-    zypper --quiet --root $cache/partial-$arch-packages --non-interactive --gpg-auto-import-keys update || return 1
+    # Leap update repos were rearranged
+    if [ $DISTRO == "leap/42.1" ]; then
+        zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/update/$DISTRO/oss/ update || return 1
+    else
+        zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update || return 1
+    fi
+       zypper --quiet --root $cache/partial-$arch-packages --non-interactive --gpg-auto-import-keys update || return 1
     zypper --root $cache/partial-$arch-packages --non-interactive in --auto-agree-with-licenses --download-only zypper lxc patterns-openSUSE-base bash iputils sed tar rsyslog || return 1
     cat > $cache/partial-$arch-packages/opensuse.conf << EOF
 Preinstall: aaa_base bash coreutils diffutils
@@ -157,7 +162,7 @@ Support: ncurses-utils
 Support: iputils
 Support: udev
 Support: netcfg
-Support: dhcpcd hwinfo insserv-compat module-init-tools openSUSE-release openssh
+Support: hwinfo insserv-compat module-init-tools openSUSE-release openssh
 Support: pwdutils rpcbind sysconfig
 
 Ignore: rpm:suse-build-key,build-key
@@ -169,6 +174,18 @@ EOF
        echo "Support: python3-base" >> $cache/partial-$arch-packages/opensuse.conf
     fi
 
+    # dhcpcd is not in the default repos with Leap 42.1
+    if [ $DISTRO != "leap/42.1" ]
+    then
+    echo "Support: dhcpcd" >> $cache/partial-$arch-packages/opensuse.conf
+    fi
+
+    # Leap doesn't seem to have iproute2 utils installed
+    if [ $DISTRO == "leap/42.1" ]
+    then
+    echo "Support: net-tools iproute2" >> $cache/partial-$arch-packages/opensuse.conf
+    fi
+
     if [ "$arch" = "i686" ]; then
         mkdir -p $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/i686/
         for i in "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/i586/*" ; do
@@ -185,7 +202,11 @@ EOF
 
     CLEAN_BUILD=1 BUILD_ARCH="$arch" BUILD_ROOT="$cache/partial-$arch" BUILD_DIST="$cache/partial-$arch-packages/opensuse.conf" PATH="$PATH:/usr/lib/build" /usr/lib/build/init_buildsystem  --clean --configdir /usr/lib/build/configs --cachedir $cache/partial-$arch-cache --repository $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/$arch --repository $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/noarch --repository $cache/partial-$arch-packages/var/cache/zypp/packages/update/$arch --repository $cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch || return 1
     chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss repo-oss || return 1
-    chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update || return 1
+    if [ $DISTRO == "leap/42.1" ]; then
+        chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/update/$DISTRO/oss update || return 1
+    else
+        chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update || return 1
+    fi
 #   really clean the image
     rm -fr $cache/partial-$arch/{.build,.guessed_dist,.srcfiles*,installed-pkg}
     rm -fr $cache/partial-$arch/dev
@@ -227,7 +248,8 @@ copy_opensuse()
 
 install_opensuse()
 {
-    cache="@LOCALSTATEDIR@/cache/lxc/opensuse/$DISTRO"
+    # Allow the cache base to be set by environment variable
+    cache="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/opensuse/$DISTRO}"
     rootfs=$1
     mkdir -p @LOCALSTATEDIR@/lock/subsys/
     (
@@ -350,7 +372,7 @@ EOF
 
 clean()
 {
-    cache="@LOCALSTATEDIR@/cache/lxc/opensuse"
+    cache="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/opensuse}"
 
     if [ ! -e $cache ]; then
         exit 0
@@ -443,6 +465,11 @@ else
            echo "Selected openSUSE 13.2"
            ;;
 
+       42.1|leap/42.1|leap)
+           echo "Selected openSUSE Leap 42.1"
+           DISTRO="leap/42.1"
+           ;;
+
        *)
            echo "You have chosen an invalid release, quitting..."
            exit 1
index fbd0fd2..d5a1514 100644 (file)
@@ -440,6 +440,31 @@ EOF
     # start with a clean /var/log/messages
     rm -f $container_rootfs/var/log/messages
 
+    # set initial timezone as on host
+    if [ -f /etc/sysconfig/clock ]; then
+        . /etc/sysconfig/clock
+        if [ $container_release_major = "5" -o $container_release_major = "6" ]; then
+                echo ZONE=$ZONE > $container_rootfs/etc/sysconfig/clock
+                chroot $container_rootfs tzdata-update
+        else
+                ZONE="${ZONE// /_}"
+                chroot $container_rootfs ln -sf ../usr/share/zoneinfo/$ZONE /etc/localtime
+        fi
+    else
+        ZONE=`readlink /etc/localtime | sed -s "s/\.\.\/usr\/share\/zoneinfo\///g"`
+        if [ "$ZONE" ]; then
+                if [ $container_release_major = "5" -o $container_release_major = "6" ]; then
+                        echo ZONE=$ZONE > $container_rootfs/etc/sysconfig/clock
+                        chroot $container_rootfs tzdata-update
+                else
+                        # if /etc/localtime is a symlink, this should preserve it.
+                        cp -a /etc/localtime $container_rootfs/etc/localtime
+                fi
+        else
+                echo "Timezone in container is not configured. Adjust it manually."
+        fi
+    fi
+
     # add oracle user, set root password
     chroot $container_rootfs useradd -m -s /bin/bash oracle
     echo "oracle:oracle" | chroot $container_rootfs chpasswd
index 3e2a8f2..48cde46 100644 (file)
@@ -44,7 +44,7 @@ export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 [ -r /etc/default/lxc ] && . /etc/default/lxc
 
 DLSCHEME=${DLSCHEME:-"http"}
-MIRRORSRV=${MIRRORSRV:-"www.ring.gr.jp"}
+MIRRORSRV=${MIRRORSRV:-"repository.plamolinux.org"}
 MIRRORPATH=${MIRRORPATH:-"/pub/linux/Plamo"}
 CATEGORIES=${CATEGORIES-"00_base 01_minimum"}
 EXTRACTGRS=${EXTRACTGRS-""}
@@ -292,7 +292,7 @@ usage() {
 prog=`basename $0`
 path="" ; name="" ; rootfs=""
 clean=0
-release=${release:-5.x}
+release=${release:-6.x}
 arch=`uname -m | sed 's/i.86/x86/'` ; hostarch=$arch
 bindhome=""
 sopts=hp:n:cr:a:b:
@@ -336,7 +336,7 @@ if [ `id -u` -ne 0 ] ; then
   echo "This script should be run as 'root'."
   exit 1
 fi
-cache=@LOCALSTATEDIR@/cache/lxc
+cache="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc}"
 ptcache=$cache/partial-${prog##*-}-$release-$arch
 dlcache=$cache/cache-${prog##*-}-$release-$arch
 rtcache=$cache/rootfs-${prog##*-}-$release-$arch
diff --git a/templates/lxc-slackware.in b/templates/lxc-slackware.in
new file mode 100644 (file)
index 0000000..c8e8e73
--- /dev/null
@@ -0,0 +1,795 @@
+#!/bin/bash
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@free.fr>
+
+# Template for slackware by Matteo Bernardini <ponce@slackbuilds.org>
+# some parts are taken from the debian one (used as model)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Detect use under userns (unsupported)
+for arg in "$@"; do
+    [ "$arg" = "--" ] && break
+    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
+        echo "This template can't be used for unprivileged containers." 1>&2
+        echo "You may want to try the \"download\" template instead." 1>&2
+        exit 1
+    fi
+done 
+
+# Add some directories to PATH in case we create containers with sudo
+export PATH=/sbin:/usr/sbin:$PATH
+
+cache=${cache:-/var/cache/lxc/slackware}
+
+# Use the primary Slackware site by default, but please consider changing
+# this to a closer mirror site.
+MIRROR=${MIRROR:-http://ftp.slackware.com/pub/slackware}
+
+if [ -z "$arch" ]; then
+case "$( uname -m )" in
+    i?86) arch=i486 ;;
+    arm*) arch=arm ;;
+       *) arch=$( uname -m ) ;;
+esac
+fi
+
+LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
+
+configure_slackware()
+{
+rootfs=$1
+hostname=$2
+
+echo "Configuring..." ; echo
+
+# The next part contains excerpts taken from SeTconfig (written by
+# Patrick Volkerding) from the slackware setup disk.
+# But before pasting them just set a variable to use them as they are 
+T_PX=$rootfs
+
+( cd $T_PX ; chmod 755 ./ )
+( cd $T_PX ; chmod 755 ./var )
+if [ -d $T_PX/usr/src/linux ]; then
+  chmod 755 $T_PX/usr/src/linux
+fi
+if [ ! -d $T_PX/proc ]; then
+  mkdir $T_PX/proc
+  chown root.root $T_PX/proc
+fi
+if [ ! -d $T_PX/sys ]; then
+  mkdir $T_PX/sys
+  chown root.root $T_PX/sys
+fi
+chmod 1777 $T_PX/tmp
+if [ ! -d $T_PX/var/spool/mail ]; then
+  mkdir -p $T_PX/var/spool/mail
+  chmod 755 $T_PX/var/spool
+  chown root.mail $T_PX/var/spool/mail
+  chmod 1777 $T_PX/var/spool/mail
+fi
+
+echo "#!/bin/sh" > $T_PX/etc/rc.d/rc.keymap
+echo "# Load the keyboard map.  More maps are in /usr/share/kbd/keymaps." \
+  >> $T_PX/etc/rc.d/rc.keymap
+echo "if [ -x /usr/bin/loadkeys ]; then" >> $T_PX/etc/rc.d/rc.keymap
+echo " /usr/bin/loadkeys us" >> $T_PX/etc/rc.d/rc.keymap
+echo "fi" >> $T_PX/etc/rc.d/rc.keymap
+chmod 755 $T_PX/etc/rc.d/rc.keymap
+
+# Network configuration is left to the user, that have to edit
+# /etc/rc.d/rc.inet1.conf and /etc/resolv.conf of the container
+# just set the hostname
+cat <<EOF > $rootfs/etc/HOSTNAME
+$hostname.example.net
+EOF
+cp $rootfs/etc/HOSTNAME $rootfs/etc/hostname
+
+# make needed devices, from Chris Willing's MAKEDEV.sh
+# http://www.vislab.uq.edu.au/howto/lxc/MAKEDEV.sh
+DEV=$rootfs/dev
+mkdir -p ${DEV}
+mknod -m 666 ${DEV}/null c 1 3
+mknod -m 666 ${DEV}/zero c 1 5
+mknod -m 666 ${DEV}/random c 1 8
+mknod -m 666 ${DEV}/urandom c 1 9
+mkdir -m 755 ${DEV}/pts
+mkdir -m 1777 ${DEV}/shm
+mknod -m 666 ${DEV}/tty c 5 0
+mknod -m 600 ${DEV}/console c 5 1
+mknod -m 666 ${DEV}/tty0 c 4 0
+mknod -m 666 ${DEV}/tty1 c 4 1
+mknod -m 666 ${DEV}/tty2 c 4 2
+mknod -m 666 ${DEV}/tty3 c 4 3
+mknod -m 666 ${DEV}/tty4 c 4 4
+mknod -m 666 ${DEV}/tty5 c 4 5
+mknod -m 666 ${DEV}/full c 1 7
+mknod -m 600 ${DEV}/initctl p
+mknod -m 660 ${DEV}/loop0 b 7 0
+mknod -m 660 ${DEV}/loop1 b 7 1
+ln -s pts/ptmx ${DEV}/ptmx
+ln -s /proc/self/fd ${DEV}/fd
+
+echo "Adding an etc/fstab"
+cat >$rootfs/etc/fstab <<EOF
+none /run tmpfs defaults,mode=0755 0 0
+EOF
+
+# simplify rc.6 and rc.S, http://www.vislab.uq.edu.au/howto/lxc/create_container.html
+# and some other small fixes for a clean boot
+cat >$rootfs/tmp/rcs.patch <<'EOF'
+--- ./etc/rc.orig/rc.6 2012-08-15 01:03:12.000000000 +0200
++++ ./etc/rc.d/rc.6    2013-02-17 10:26:30.888839354 +0100
+@@ -9,6 +9,12 @@
+ # Author:     Miquel van Smoorenburg <miquels@drinkel.nl.mugnet.org>
+ # Modified by:  Patrick J. Volkerding, <volkerdi@slackware.com>
+ #
++# minor tweaks for an lxc container
++# by Matteo Bernardini <ponce@slackbuilds.org>,
++# based also on Chris Willing's modifications
++# http://www.vislab.uq.edu.au/howto/lxc/rc.6
++# a check for a container variable is made to jump sections
++container="lxc"
+ # Set the path.
+ PATH=/sbin:/etc:/bin:/usr/bin
+@@ -37,6 +43,9 @@
+               ;;
+ esac
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Save the system time to the hardware clock using hwclock --systohc.
+ if [ -x /sbin/hwclock ]; then
+   # Check for a broken motherboard RTC clock (where ioports for rtc are
+@@ -53,6 +62,8 @@
+   fi
+ fi
++fi # end container check
++
+ # Run any local shutdown scripts:
+ if [ -x /etc/rc.d/rc.local_shutdown ]; then
+   /etc/rc.d/rc.local_shutdown stop
+@@ -148,6 +159,9 @@
+   sleep 2
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Shut down PCMCIA devices:
+ if [ -x /etc/rc.d/rc.pcmcia ]; then
+   . /etc/rc.d/rc.pcmcia stop
+@@ -155,11 +169,16 @@
+   /bin/sleep 5
+ fi
++fi # end container check
++
+ # Turn off process accounting:
+ if [ -x /sbin/accton -a -r /var/log/pacct ]; then
+   /sbin/accton off
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Terminate acpid before syslog:
+ if [ -x /etc/rc.d/rc.acpid -a -r /var/run/acpid.pid ]; then # quit
+   . /etc/rc.d/rc.acpid stop
+@@ -170,6 +189,8 @@
+   sh /etc/rc.d/rc.udev force-stop
+ fi
++fi # end container check
++
+ # Kill all remaining processes.
+ if [ ! "$1" = "fast" ]; then
+   echo "Sending all processes the SIGTERM signal."
+@@ -179,6 +200,9 @@
+   /sbin/killall5 -9
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Try to turn off quota.
+ if /bin/grep -q quota /etc/fstab ; then
+   if [ -x /sbin/quotaoff ]; then
+@@ -187,6 +211,8 @@
+   fi
+ fi
++fi # end container check
++
+ # Carry a random seed between reboots.
+ echo "Saving random seed from /dev/urandom in /etc/random-seed."
+ # Use the pool size from /proc, or 512 bytes:
+@@ -205,6 +231,9 @@
+   rm -f /var/lock/subsys/*
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Turn off swap:
+ echo "Turning off swap."
+ /sbin/swapoff -a
+@@ -216,6 +245,8 @@
+ echo "Remounting root filesystem read-only."
+ /bin/mount -v -n -o remount,ro /
++fi # end container check
++
+ # This never hurts:
+ /bin/sync
+@@ -240,12 +271,17 @@
+   done
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Deactivate LVM volume groups:
+ if [ -r /etc/lvmtab -o -d /etc/lvm/backup ]; then
+   echo "Deactivating LVM volume groups:"
+   /sbin/vgchange -an --ignorelockingfailure
+ fi
++fi # end container check
++
+ # This never hurts again (especially since root-on-LVM always fails
+ # to deactivate the / logical volume...  but at least it was
+ # remounted as read-only first)
+@@ -258,6 +294,9 @@
+ # This is to ensure all processes have completed on SMP machines:
+ wait
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ if [ -x /sbin/genpowerd ]; then
+   # See if this is a powerfail situation:
+   if /bin/egrep -q "FAIL|SCRAM" /etc/upsstatus 2> /dev/null ; then
+@@ -274,6 +313,13 @@
+   fi
+ fi
++else
++
++# confirm successful shutdown of the container
++echo ; echo "* container stopped. *" ; echo
++
++fi # end container check
++
+ # Now halt (poweroff with APM or ACPI enabled kernels) or reboot.
+ if [ "$command" = "reboot" ]; then
+   echo "Rebooting."
+--- ./etc/rc.orig/rc.S 2012-09-13 21:38:34.000000000 +0200
++++ ./etc/rc.d/rc.S    2013-02-17 09:39:41.579799641 +0100
+@@ -4,9 +4,18 @@
+ #
+ # Mostly written by:  Patrick J. Volkerding, <volkerdi@slackware.com>
+ #
++# minor tweaks for an lxc container
++# by Matteo Bernardini <ponce@slackbuilds.org>,
++# based also on Chris Willing's modifications
++# http://www.vislab.uq.edu.au/howto/lxc/rc.S
++# a check for a container variable is made to jump sections
++container="lxc"
+ PATH=/sbin:/usr/sbin:/bin:/usr/bin
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Try to mount /proc:
+ /sbin/mount -v proc /proc -n -t proc 2> /dev/null
+@@ -254,10 +263,27 @@
+   read junk;
+ fi # Done checking root filesystem
++else
++  # We really don't want to start udev in the container
++  if [ -f /etc/rc.d/rc.udev ]; then
++    chmod -x /etc/rc.d/rc.udev
++  fi
++  # Alsa won't work
++  if [ -f /etc/rc.d/rc.alsa ]; then
++    chmod -x /etc/rc.d/rc.alsa
++  fi
++  # This too
++  if [ -f /etc/rc.d/rc.loop ]; then
++    chmod -x /etc/rc.d/rc.loop
++  fi
++fi # end container check
+ # Any /etc/mtab that exists here is old, so we start with a new one:
+ /bin/rm -f /etc/mtab{,~,.tmp} && /bin/touch /etc/mtab
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Add entry for / to /etc/mtab:
+ /sbin/mount -f -w /
+@@ -337,6 +363,8 @@
+ # mounted read-write.
+ /sbin/swapon -a 2> /dev/null
++fi # end container check
++
+ # Clean up some temporary files:
+ rm -f /var/run/* /var/run/*/* /var/run/*/*/* /etc/nologin \
+   /etc/dhcpc/*.pid /etc/forcefsck /etc/fastboot \
+@@ -364,7 +392,7 @@
+ # if the first line of that file begins with the word 'Linux'.
+ # You are free to modify the rest of the file as you see fit.
+ if [ -x /bin/sed ]; then
+-  /bin/sed -i "{1s/^Linux.*/$(/bin/uname -sr)\./}" /etc/motd
++  /bin/sed -i "{1s/^Linux.*/$(/bin/uname -sr) lxc container\./}" /etc/motd
+ fi
+ # If there are SystemV init scripts for this runlevel, run them.
+@@ -372,6 +400,9 @@
+   . /etc/rc.d/rc.sysvinit
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Run serial port setup script:
+ # CAREFUL!  This can make some systems hang if the rc.serial script isn't
+ # set up correctly.  If this happens, you may have to edit the file from a
+@@ -380,6 +411,8 @@
+   sh /etc/rc.d/rc.serial start
+ fi
++fi # end container check
++
+ # Carry an entropy pool between reboots to improve randomness.
+ if [ -f /etc/random-seed ]; then
+   echo "Using /etc/random-seed to initialize /dev/urandom."
+--- ./etc/rc.orig/rc.M 2012-09-25 19:47:07.000000000 +0200
++++ ./etc/rc.d/rc.M    2013-02-17 09:39:41.579799641 +0100
+@@ -10,6 +10,10 @@
+ # Author:     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ #             Heavily modified by Patrick Volkerding <volkerdi@slackware.com>
+ #
++# minor tweaks for an lxc container
++# by Matteo Bernardini <ponce@slackbuilds.org>:
++# a check for a container variable is made to jump sections
++container="lxc"
+ # Tell the viewers what's going to happen.
+ echo "Going multiuser..."
+@@ -20,6 +24,9 @@
+   /sbin/ldconfig &
+ fi
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Screen blanks after 15 minutes idle time, and powers down in one hour
+ # if the kernel supports APM or ACPI power management:
+ /bin/setterm -blank 15 -powersave powerdown -powerdown 60
+@@ -33,6 +40,8 @@
+   /bin/hostname darkstar
+ fi
++fi # end container check
++
+ # Set the permissions on /var/log/dmesg according to whether the kernel
+ # permits non-root users to access kernel dmesg information:
+ if [ -r /proc/sys/kernel/dmesg_restrict ]; then
+@@ -135,6 +144,9 @@
+ chmod 755 / 2> /dev/null
+ chmod 1777 /tmp /var/tmp
++# lxc container check
++if [ ! $container = "lxc" ]; then
++
+ # Start APM or ACPI daemon.
+ # If APM is enabled in the kernel, start apmd:
+ if [ -e /proc/apm ]; then
+@@ -146,6 +158,8 @@
+   . /etc/rc.d/rc.acpid start
+ fi
++fi # end container check
++
+ # Update any existing icon cache files:
+ if find /usr/share/icons 2> /dev/null | grep -q icon-theme.cache ; then
+   for theme_dir in /usr/share/icons/* ; do
+--- ./etc/rc.orig/rc.inet1     2012-08-05 19:13:27.000000000 +0200
++++ ./etc/rc.d/rc.inet1        2013-02-17 09:39:41.579799641 +0100
+@@ -3,6 +3,11 @@
+ # This script is used to bring up the various network interfaces.
+ #
+ # @(#)/etc/rc.d/rc.inet1 10.2  Sun Jul 24 12:45:56 PDT 2005  (pjv)
++#
++# minor tweaks for an lxc container
++# by Matteo Bernardini <ponce@slackbuilds.org>:
++# a check for a container variable is made to jump sections
++container="lxc"
+ ############################
+ # READ NETWORK CONFIG FILE #
+@@ -105,6 +110,10 @@
+     [ "${IFNAME[$i]}" = "${1}" ] && break
+     i=$(($i+1))
+   done
++
++  # lxc container check
++  if [ ! $container = "lxc" ]; then
++
+   # If the interface is a bridge, then create it first:
+   [ -n "${BRNICS[$i]}" ] && br_open $i
+   # If the interface isn't in the kernel yet (but there's an alias for it in
+@@ -115,6 +124,9 @@
+       /sbin/modprobe ${1}
+     fi
+   fi
++
++  fi # end container check
++
+   if grep `echo ${1}: | cut -f 1 -d :`: /proc/net/dev 1> /dev/null ; then # interface exists
+     if ! /sbin/ifconfig | grep -w "${1}" 1>/dev/null || \
+       ! /sbin/ifconfig ${1} | grep -w inet 1> /dev/null ; then # interface not up or not configured
+EOF
+( cd $rootfs ; patch -p1 < tmp/rcs.patch ; rm tmp/rcs.patch )
+
+# restart rc.inet1 to have routing for the loop device
+echo "/etc/rc.d/rc.inet1 restart" >> $rootfs/etc/rc.d/rc.local
+
+# reduce the number of local consoles: two should be enough
+sed -i '/^c3\|^c4\|^c5\|^c6/s/^/# /' $rootfs/etc/inittab
+
+# better not use this in a container
+sed -i 's/.*genpowerfail.*//' $rootfs/etc/inittab
+
+# add a message to rc.local that confirms successful container startup
+echo "echo ; echo \"* container $name started. *\" ; echo" >> $rootfs/etc/rc.d/rc.local
+
+# set a default combination for the luggage
+echo "root:root" | chroot $rootfs chpasswd
+echo "Root default password is 'root', please change it!"
+
+# borrow the time configuration from the local machine
+cp -a /etc/localtime $rootfs/etc/localtime
+
+return 0
+}
+
+copy_slackware()
+{
+rootfs=$1
+
+# make a local copy of the installed filesystem
+echo -n "Copying rootfs to $rootfs..."
+mkdir -p $rootfs
+cp -a $cache/rootfs-$release-$arch/* $rootfs/ || exit 1
+
+# fix fstab with the actual path
+sed -i "s|$cache/rootfs-$release-$arch|$rootfs|" $rootfs/etc/fstab
+
+return 0
+}
+
+install_slackware()
+{
+rootfs=$1
+mkdir -p /var/lock/subsys/
+(
+flock -n -x 200
+if [ $? -ne 0 ]; then
+       echo "Cache repository is busy."
+       return 1
+fi
+
+if [ "$arch" == "x86_64" ]; then
+        PKGMAIN=slackware64
+elif [ "$arch" == "arm" ]; then
+        PKGMAIN=slackwarearm
+else
+       PKGMAIN=slackware
+fi
+
+export CONF=$cache/slackpkg-conf
+export ROOT=$cache/rootfs-$release-$arch
+
+mkdir -p $cache/cache-$release-$arch $cache/rootfs-$release-$arch \
+  $cache/slackpkg-$release-$arch $CONF/templates
+
+echo "$MIRROR/$PKGMAIN-$release/" > $CONF/mirrors
+touch $CONF/blacklist
+
+cat <<EOF > $CONF/slackpkg.conf
+# v2.8
+ARCH=$arch
+TEMP=$cache/cache-$release-$arch
+WORKDIR=$cache/slackpkg-$release-$arch
+DELALL=off
+CHECKMD5=on
+CHECKGPG=on
+CHECKSIZE=off
+PRIORITY=( patches %PKGMAIN extra pasture testing )
+POSTINST=on
+ONLY_NEW_DOTNEW=off
+ONOFF=on
+DOWNLOAD_ALL=on
+DIALOG=off
+BATCH=on
+DEFAULT_ANSWER=y
+USE_INCLUDES=on
+SPINNING=off
+EOF
+
+# thanks to Vincent Batts for this list of packages
+# (that I modified a little :P)
+# http://connie.slackware.com/~vbatts/minimal/
+cat <<EOF > $CONF/templates/minimal-lxc.template
+aaa_base
+aaa_elflibs
+aaa_terminfo
+bash
+bin
+bzip2
+coreutils
+dhcpcd
+dialog
+diffutils
+e2fsprogs
+elvis
+etc
+findutils
+gawk
+glibc-solibs
+gnupg
+grep
+gzip
+iputils
+logrotate
+mpfr
+net-tools
+network-scripts
+ncurses
+openssh
+openssl-solibs
+pkgtools
+procps-ng
+sed
+shadow
+sharutils
+slackpkg
+sysklogd
+sysvinit
+sysvinit-functions
+sysvinit-scripts
+tar
+udev
+util-linux
+wget
+which
+xz
+EOF
+
+TEMPLATE=${TEMPLATE:-minimal-lxc}
+if [ ! "$TEMPLATE" = "minimal-lxc" ]; then
+  if [ -f /etc/slackpkg/templates/$TEMPLATE.template ]; then
+    cat /etc/slackpkg/templates/$TEMPLATE.template \
+      > $CONF/templates/$TEMPLATE.template
+  else
+    TEMPLATE="minimal-lxc"
+  fi
+fi
+
+# clean previous installs
+rm -fR $ROOT/*
+
+slackpkg -default_answer=n update 
+slackpkg install-template $TEMPLATE
+
+# add a slackpkg default mirror
+echo "$MIRROR/$PKGMAIN-$release/" >> $ROOT/etc/slackpkg/mirrors
+
+# blacklist the devs package (we have to use our premade devices).
+# do the same with the kernel packages (we use the host's one),
+# but leave available headers and sources
+echo "devs" >> $ROOT/etc/slackpkg/blacklist
+sed -i \
+  -e "s|^#kernel-|kernel-|" \
+  -e "s|^kernel-headers|#kernel-headers|" \
+  -e "s|^kernel-source|#kernel-source|" \
+  $ROOT/etc/slackpkg/blacklist
+
+# force klog to use the system call interface to the kernel message
+# buffers - needed for unprivileged containers
+sed -i 's|3\ \-x|3 -x -s|' $ROOT/etc/rc.d/rc.syslog || true
+
+return 0
+
+) 200>/var/lock/subsys/lxc
+
+return $?
+}
+
+copy_configuration()
+{
+path=$1
+rootfs=$2
+name=$3
+
+cat <<EOF >> $path/config
+
+lxc.utsname = $name
+lxc.arch = $arch
+
+lxc.mount = $rootfs/etc/fstab
+
+lxc.include = ${LXC_TEMPLATE_CONFIG}/slackware.common.conf
+EOF
+
+if [ $? -ne 0 ]; then
+       echo "Failed to add configuration."
+       return 1
+fi
+
+return 0
+}
+
+clean()
+{
+if [ ! -e $cache ]; then
+       exit 0
+fi
+
+# lock, so we won't purge while someone is creating a repository
+(
+flock -n -x 200
+if [ $? != 0 ]; then
+       echo "Cache repository is busy."
+       exit 1
+fi
+
+echo -n "Purging the download cache..."
+rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
+exit 0
+
+) 200>/var/lock/subsys/lxc
+}
+
+usage()
+{
+cat <<EOF
+$1 -h|--help -p|--path=<path> --clean
+EOF
+return 0
+}
+
+options=$(getopt -o hp:n:a:r:c -l help,rootfs:,path:,name:,arch:,release:,clean --  "$@")
+if [ $? -ne 0 ]; then
+       usage $(basename $0)
+       exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+case "$1" in
+        -h|--help)      usage $0 && exit 0;;
+        -p|--path)      path=$2; shift 2;;
+       --rootfs)       rootfs=$2; shift 2;;
+       -a|--arch)      arch=$2; shift 2;; 
+       -r|--release)   release=$2; shift 2;;
+       -n|--name)      name=$2; shift 2;;
+       -c|--clean)     clean=$2; shift 2;;
+        --)             shift 1; break ;;
+        *)              break ;;
+esac
+done
+
+if [ ! -z "$clean" -a -z "$path" ]; then
+       clean || exit 1
+       exit 0
+fi
+
+type installpkg
+if [ $? -ne 0 ]; then
+       echo "'installpkg' command is missing."
+       exit 1
+fi
+
+type slackpkg
+if [ $? -ne 0 ]; then
+       echo "'slackpkg' command is missing."
+       exit 1
+fi
+
+if [ -z "$path" ]; then
+       echo "'path' parameter is required."
+       exit 1
+fi
+
+if [ "$(id -u)" != "0" ]; then
+       echo "This script should be run as 'root'."
+       exit 1
+fi
+
+# If no release version was specified, use current
+release=${release:-current}
+
+if [ -z "$name" ]; then
+       # no name given? set a default one
+       name=slackwarecontainer
+fi
+
+# detect rootfs
+config="$path/config"
+if [ -z "$rootfs" ]; then
+       if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
+               rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
+       else
+               rootfs=$path/rootfs
+       fi
+fi
+
+echo
+
+set -e
+
+install_slackware $rootfs
+if [ $? -ne 0 ]; then
+       echo "Failed to install slackware."
+       exit 1
+fi
+
+echo
+
+configure_slackware $cache/rootfs-$release-$arch $name
+if [ $? -ne 0 ]; then
+       echo "Failed to configure slackware for a container."
+       exit 1
+fi
+
+echo
+
+rootfs=$path/rootfs
+copy_slackware $rootfs
+if [ $? -ne 0 ]; then
+       echo "Failed to copy rootfs."
+       exit 1
+fi
+
+echo
+
+copy_configuration $path $rootfs $name
+if [ $? -ne 0 ]; then
+       echo "Failed to write configuration file."
+       exit 1
+fi
+
+if [ ! -z $clean ]; then
+       clean || exit 1
+       exit 0
+fi
diff --git a/templates/lxc-sparclinux.in b/templates/lxc-sparclinux.in
new file mode 100644 (file)
index 0000000..cfb893a
--- /dev/null
@@ -0,0 +1,696 @@
+#!/bin/sh
+#
+# Template script for generating Linux for SPARC for LXC
+# based on lxc-fedora, lxc-ubuntu
+#
+# Copyright © 2011 Wim Coekaerts <wim.coekaerts@oracle.com>
+# Copyright © 2012 Dwight Engen <dwight.engen@oracle.com>
+# Copyright � 2015 Wim Coekaerts <wim.coekaerts@oracle.com>
+#
+# Modified for Oracle Linux 5
+# Wim Coekaerts <wim.coekaerts@oracle.com>
+#
+# Modified for Oracle Linux 6,7 combined OL4,5,6 into one template script
+# Dwight Engen <dwight.engen@oracle.com>
+#
+# Modified for Linux for SPARC 1.0
+# Wim Coekaerts <wim.coekaerts@oracle.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+# Detect use under userns (unsupported)
+for arg in "$@"; do
+    [ "$arg" = "--" ] && break
+    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
+        echo "This template can't be used for unprivileged containers." 1>&2
+        echo "You may want to try the \"download\" template instead." 1>&2
+        exit 1
+    fi
+done
+
+# Make sure the usual locations are in PATH
+export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+# use virbr0 that is setup by default by libvirtd
+lxc_network_type=veth
+lxc_network_link=virbr0
+
+die()
+{
+    echo "failed: $1"
+    exit 1
+}
+
+is_btrfs_subvolume()
+{
+    if which btrfs >/dev/null 2>&1 && \
+       btrfs subvolume list "$1" >/dev/null 2>&1; then
+        return 0
+    fi
+    return 1
+}
+
+can_chcon()
+{
+    if which chcon >/dev/null 2>&1; then
+        selinuxenabled >/dev/null 2>&1
+        return $?
+    fi
+    return 1
+}
+
+# fix up the container_rootfs
+container_rootfs_patch()
+{
+    echo "Patching container rootfs $container_rootfs for Linux for SPARC $container_release_major.$container_release_minor"
+
+    # copy ourself into the container to be used to --patch the rootfs when
+    # yum update on certain packages is done. we do this here instead of in
+    # container_rootfs_configure() in case the patching done in this function
+    # is updated in the future, we can inject the updated version of ourself
+    # into older containers.
+    if [ $container_rootfs != "/" ]; then
+        cp -f `readlink -f $0` $container_rootfs/usr/bin/lxc-patch
+        mkdir -p $container_rootfs/usr/share/yum-plugins
+        cp @DATADIR@/lxc/lxc-patch.py $container_rootfs/usr/share/yum-plugins
+        mkdir -p $container_rootfs/etc/yum/pluginconf.d
+        cat <<EOF > $container_rootfs/etc/yum/pluginconf.d/lxc-patch.conf
+[main]
+enabled=1
+packages=dbus,initscripts,iptables,openssh-server,setup,selinux-policy,readahead,udev,util-linux,util-linux-ng
+EOF
+    fi
+
+    # "disable" selinux in the guest. The policy in the container isn't
+    # likely to match the hosts (unless host == guest exactly) and the
+    # kernel can only be enforcing one policy.
+    #
+    mkdir -p $container_rootfs/selinux
+    echo 0 > $container_rootfs/selinux/enforce
+    if [ -e $container_rootfs/etc/selinux/config ]; then
+        sed -i 's|SELINUX=enforcing|SELINUX=disabled|' $container_rootfs/etc/selinux/config
+    else
+        mkdir -p $container_rootfs/etc/selinux
+        echo "SELINUX=disabled" >$container_rootfs/etc/selinux/config
+    fi
+    sed -i 's|session[ \t]*required[ \t]*pam_selinux.so[ \t]*close|#session required pam_selinux.so close|' $container_rootfs/etc/pam.d/login
+    sed -i 's|session[ \t]*required[ \t]*pam_selinux.so[ \t]*open|#session required pam_selinux.so open|' $container_rootfs/etc/pam.d/login
+    sed -i 's|session[ \t]*required[ \t]*pam_selinux.so[ \t]*close|#session required pam_selinux.so close|' $container_rootfs/etc/pam.d/sshd
+    sed -i 's|session[ \t]*required[ \t]*pam_selinux.so[ \t]*open|#session required pam_selinux.so open|' $container_rootfs/etc/pam.d/sshd
+
+    # setting /proc/$$/loginuid doesn't work under user namespace, which
+    # prevents logins from working
+    sed -i 's|session[ \t]*required[ \t]*pam_loginuid.so|#session required pam_loginuid.so|' $container_rootfs/etc/pam.d/sshd
+    sed -i 's|session[ \t]*required[ \t]*pam_loginuid.so|#session required pam_loginuid.so|' $container_rootfs/etc/pam.d/login
+
+    if [ -f $container_rootfs/usr/sbin/selinuxenabled ]; then
+        mv $container_rootfs/usr/sbin/selinuxenabled $container_rootfs/usr/sbin/selinuxenabled.lxcorig
+        ln -s /bin/false $container_rootfs/usr/sbin/selinuxenabled
+    fi
+
+    # ensure /dev/ptmx refers to the newinstance devpts of the container, or
+    # pty's will get crossed up with the hosts (https://lkml.org/lkml/2012/1/23/512)
+    rm -f $container_rootfs/dev/ptmx
+    ln -s pts/ptmx $container_rootfs/dev/ptmx
+
+    # silence error in checking for selinux
+    sed -i 's|cat /proc/self/attr/current|cat /proc/self/attr/current 2>/dev/null|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|cat /proc/self/attr/current|cat /proc/self/attr/current 2>/dev/null|' $container_rootfs/etc/rc.d/rc.sysinit
+
+    # disable ipv6
+    rm -f $container_rootfs/etc/sysconfig/network-scripts/init.ipv6-global
+
+    # remove module stuff for iptables it just shows errors that are not
+    # relevant in a container
+    if [ -f "$container_rootfs/etc/sysconfig/iptables-config" ]; then
+        sed -i 's|IPTABLES_MODULES=".*|IPTABLES_MODULES=""|' $container_rootfs/etc/sysconfig/iptables-config
+        sed -i 's|IPTABLES_MODULES_UNLOAD=".*|IPTABLES_MODULES_UNLOAD="no"|' $container_rootfs/etc/sysconfig/iptables-config
+    fi
+
+    # disable readahead in the container
+    if [ $container_release_major = "1" -a -e $container_rootfs/etc/sysconfig/readahead ]; then
+        rm -f $container_rootfs/etc/init/readahead-collector.conf
+        rm -f $container_rootfs/etc/init/readahead-disable-services.conf
+        sed -i 's|READAHEAD="yes"|READAHEAD="no"|' $container_rootfs/etc/sysconfig/readahead
+    fi
+
+
+    # no need to attempt to mount /
+    sed -i 's|mount -f /$|# LXC mount -f /|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|mount -f /$|# LXC mount -f /|' $container_rootfs/etc/rc.d/rc.sysinit
+    sed -i 's|action \$"Remounting root filesystem|/bin/true # LXC action $"Remounting root filesystem|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|action \$"Remounting root filesystem|/bin/true # LXC action $"Remounting root filesystem|' $container_rootfs/etc/rc.d/rc.sysinit
+
+    # disable udev in the container
+    sed -i 's|.sbin.start_udev||' $container_rootfs/etc/rc.sysinit
+    sed -i 's|.sbin.start_udev||' $container_rootfs/etc/rc.d/rc.sysinit
+
+    sed -i 's|\[ -x /sbin/hwclock|\[ 0 -eq 1|' $container_rootfs/etc/rc.d/init.d/halt
+    sed -i 's|^\[ -x /sbin/hwclock|\[ 0 -eq 1|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|^\[ -x /sbin/hwclock|\[ 0 -eq 1|' $container_rootfs/etc/rc.d/rc.sysinit
+    sed -i 's|^/sbin/hwclock|# LXC /sbin/nohwclock|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|^/sbin/hwclock|# LXC /sbin/nohwclock|' $container_rootfs/etc/rc.d/rc.sysinit
+
+    touch $container_rootfs/.nolvm
+
+    # fix assumptions that plymouth is available
+    sed -i 's|\[ "$PROMPT" != no \] && plymouth|[ "$PROMPT" != no ] \&\& [ -n "$PLYMOUTH" ] \&\& plymouth|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|\[ "$PROMPT" != no \] && plymouth|[ "$PROMPT" != no ] \&\& [ -n "$PLYMOUTH" ] \&\& plymouth|' $container_rootfs/etc/rc.d/rc.sysinit
+    rm -f $container_rootfs/etc/init/plymouth-shutdown.conf
+    rm -f $container_rootfs/etc/init/quit-plymouth.conf
+    rm -f $container_rootfs/etc/init/splash-manager.conf
+
+    # dont try to unmount /dev/lxc devices
+    sed -i 's|&& $1 !~ /^\\/dev\\/ram/|\&\& $2 !~ /^\\/dev\\/lxc/ \&\& $1 !~ /^\\/dev\\/ram/|' $container_rootfs/etc/init.d/halt
+
+    # don't try to unmount swap
+    sed -i 's|\[ -f /proc/swaps \]|# LXC [ -f /proc/swaps ]|' $container_rootfs/etc/init.d/halt
+
+    sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit
+    sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit
+
+    # there might be other services that are useless but the below set is a good start
+    # some of these might not exist in the image, so we silence chkconfig complaining
+    # about the service file not being found
+    for service in \
+        acpid apmd auditd autofs cpuspeed dund gpm haldaemon hidd      \
+        ip6tables irqbalance iscsi iscsid isdn kdump kudzu             \
+        lm_sensors lvm2-monitor mdmonitor microcode_ctl                        \
+        ntpd pcmcia postfix sendmail udev-post xfs ;
+    do
+        chroot $container_rootfs chkconfig 2>/dev/null $service off
+    done
+
+    for service in rsyslog ;
+    do
+        chroot $container_rootfs chkconfig 2>/dev/null $service on
+    done
+}
+
+container_rootfs_configure()
+{
+    container_rootfs_patch
+    echo "Configuring container for Linux for SPARC $container_release_major.$container_release_minor"
+
+    # configure the network to use dhcp. we set DHCP_HOSTNAME so the guest
+    # will report its name and be resolv'able by the hosts dnsmasq
+    cat <<EOF > $container_rootfs/etc/sysconfig/network-scripts/ifcfg-eth0
+DEVICE=eth0
+BOOTPROTO=dhcp
+ONBOOT=yes
+HOSTNAME=$name
+DHCP_HOSTNAME=\`hostname\`
+NM_CONTROLLED=no
+TYPE=Ethernet
+EOF
+
+    cat <<EOF > $container_rootfs/etc/sysconfig/network
+NETWORKING=yes
+NETWORKING_IPV6=no
+HOSTNAME=$name
+EOF
+
+    # set minimal hosts
+    echo "127.0.0.1 localhost $name" > $container_rootfs/etc/hosts
+
+    # this file has to exist for libvirt/Virtual machine monitor to boot the container
+    touch $container_rootfs/etc/mtab
+
+    # setup console and tty[1-4] for login. note that /dev/console and
+    # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
+    # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
+    # lxc will maintain these links and bind mount ptys over /dev/lxc/*
+    # since lxc.devttydir is specified in the config.
+
+    # allow root login on console, tty[1-4], and pts/0 for libvirt
+    echo "# LXC (Linux Containers)" >>$container_rootfs/etc/securetty
+    echo "lxc/console" >>$container_rootfs/etc/securetty
+    for i in 1 2 3 4; do
+        echo "lxc/tty$i"       >>$container_rootfs/etc/securetty
+    done
+    echo "# For libvirt/Virtual Machine Monitor" >>$container_rootfs/etc/securetty
+    for i in 0 1 2 3 4; do
+        echo "pts/$i"        >>$container_rootfs/etc/securetty
+    done
+
+    # prevent mingetty from calling vhangup(2) since it fails with userns
+    if [ -f $container_rootfs/etc/init/tty.conf ]; then
+        sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/init/tty.conf
+    fi
+
+    # create maygetty which only spawns a getty on the console when running
+    # under lxc, not libvirt-lxc which symlinks /dev/console to the same pty
+    # as /dev/tty1
+    cat <<EOF >$container_rootfs/sbin/maygetty
+#!/bin/sh
+if [ "\$container" = "lxc" ]; then
+    exec /sbin/mingetty \$@
+fi
+exec sleep infinity
+EOF
+    chmod 755 $container_rootfs/sbin/maygetty
+
+    cat <<EOF > $container_rootfs/etc/init/console.conf
+# console - getty
+#
+# This service maintains a getty on the console from the point the system is
+# started until it is shut down again.
+
+start on stopped rc RUNLEVEL=[2345]
+stop on runlevel [!2345]
+env container
+
+respawn
+exec /sbin/maygetty --nohangup --noclear /dev/console
+EOF
+
+    cat <<EOF > $container_rootfs/etc/init/power-status-changed.conf
+# power-status-changed - used to cleanly shut down the container
+#
+# This task is run whenever init receives SIGPWR
+# Used to shut down the machine.
+
+start on power-status-changed
+
+exec init 0
+EOF
+
+    # start with a clean /var/log/messages
+    rm -f $container_rootfs/var/log/messages
+
+    # set initial timezone as on host
+    if [ -f /etc/sysconfig/clock ]; then
+        . /etc/sysconfig/clock
+        echo ZONE=$ZONE > $container_rootfs/etc/sysconfig/clock
+        chroot $container_rootfs tzdata-update
+    else
+        echo "Timezone in container is not configured. Adjust it manually."
+    fi
+
+    # add oracle user, set root password
+    chroot $container_rootfs useradd -m -s /bin/bash oracle
+    echo "oracle:oracle" | chroot $container_rootfs chpasswd
+    echo "root:root" | chroot $container_rootfs chpasswd
+    printf "Added container user:\033[1moracle\033[0m password:\033[1moracle\033[0m\n"
+    printf "Added container user:\033[1mroot\033[0m password:\033[1mroot\033[0m\n"
+}
+
+# create the container's lxc config file
+container_config_create()
+{
+    echo "Create configuration file $cfg_dir/config"
+    mkdir -p $cfg_dir || die "unable to create config dir $cfg_dir"
+
+    echo "# Common configuration" >> $cfg_dir/config
+    if [ -e "@LXCTEMPLATECONFIG@/sparclinux.common.conf" ]; then
+        echo "lxc.include = @LXCTEMPLATECONFIG@/sparclinux.common.conf" >> $cfg_dir/config
+    fi
+
+    # generate a hwaddr for the container with a high mac address
+    # see http://sourceforge.net/tracker/?func=detail&aid=3411497&group_id=163076&atid=826303
+    local hwaddr="fe:`dd if=/dev/urandom bs=8 count=1 2>/dev/null |od -t x8 | \
+                      head -n 1 |awk '{print $2}' | cut -c1-10 |\
+                      sed 's/\(..\)/\1:/g; s/.$//'`"
+    cat <<EOF >> $cfg_dir/config || die "unable to create $cfg_dir/config"
+# Container configuration for Linux for SPARC $container_release_major.$container_release_minor
+lxc.arch = $arch
+lxc.utsname = $name
+EOF
+    grep -q "^lxc.rootfs" $cfg_dir/config 2>/dev/null || echo "lxc.rootfs = $container_rootfs" >> $cfg_dir/config
+
+    echo "lxc.cap.drop = sys_resource" >>$cfg_dir/config
+
+    echo "lxc.cap.drop = setfcap setpcap" >>$cfg_dir/config
+
+    echo "# Networking" >>$cfg_dir/config
+    # see if the network settings were already specified
+    lxc_network_type=`grep '^lxc.network.type' $cfg_dir/config | awk -F'[= \t]+' '{ print $2 }'`
+    if [ -z "$lxc_network_type" -a                     \
+        \( $host_distribution = "SPARCLinux" -o        \
+           $host_distribution = "Fedora" \) ]; then
+            echo "lxc.network.type = veth" >>$cfg_dir/config
+            echo "lxc.network.flags = up" >>$cfg_dir/config
+            echo "lxc.network.link = virbr0" >>$cfg_dir/config
+    fi
+
+    cat <<EOF >> $cfg_dir/config || die "unable to create $cfg_dir/config"
+lxc.network.name = eth0
+lxc.network.mtu = 1500
+lxc.network.hwaddr = $hwaddr
+EOF
+}
+
+container_rootfs_clone()
+{
+    if is_btrfs_subvolume $template_rootfs; then
+        # lxc-create already made $container_rootfs a btrfs subvolume, but
+        # in this case we want to snapshot the original subvolume so we we
+        # have to delete the one that lxc-create made
+        btrfs subvolume delete $container_rootfs
+        btrfs subvolume snapshot $template_rootfs $container_rootfs || die "btrfs clone template"
+    else
+        echo "Copying rootfs ..."
+        cp -axT $template_rootfs $container_rootfs || die "copy template"
+    fi
+}
+
+container_rootfs_repo_create()
+{
+    echo "# LXC generated .repo file" >$1
+    echo "[$2]" >>$1
+    echo "name=Linux for SPARC $container_release_major.$container_release_minor ($basearch)" >>$1
+    echo "baseurl=$3/" >>$1
+    echo "enabled=1" >>$1
+    echo "skip_if_unavailable=1" >>$1
+
+    if [ "$4" != "" ]; then
+        echo "gpgkey=$yum_url/RPM-GPG-KEY-oracle-ol$container_release_major" >>$1
+        echo "gpgcheck=1" >>$1
+    else
+        echo "gpgcheck=0" >>$1
+    fi
+}
+
+container_rootfs_dev_create()
+{
+    # create required devices. note that /dev/console will be created by lxc
+    # or libvirt itself to be a symlink to the right pty.
+    # take care to not nuke /dev in case $container_rootfs isn't set
+    dev_path="$container_rootfs/dev"
+    if [ $container_rootfs != "/" -a -d $dev_path ]; then
+        rm -rf $dev_path
+    fi
+    mkdir -p $dev_path
+    if can_chcon; then
+        # ensure symlinks created in /dev have the right context
+        chcon -t device_t $dev_path
+    fi
+    mknod -m 666  $dev_path/null c 1 3
+    mknod -m 666  $dev_path/zero c 1 5
+    mknod -m 666  $dev_path/random c 1 8
+    mknod -m 666  $dev_path/urandom c 1 9
+    mkdir -m 755  $dev_path/pts
+    mkdir -m 1777 $dev_path/shm
+    mknod -m 666  $dev_path/tty c 5 0
+    mknod -m 666  $dev_path/tty1 c 4 1
+    mknod -m 666  $dev_path/tty2 c 4 2
+    mknod -m 666  $dev_path/tty3 c 4 3
+    mknod -m 666  $dev_path/tty4 c 4 4
+    mknod -m 666  $dev_path/full c 1 7
+    mknod -m 600  $dev_path/initctl p
+
+    # set selinux labels same as host
+    if can_chcon; then
+        for node in null zero random urandom pts shm \
+                    tty tty0 tty1 tty2 tty3 tty4 full ;
+        do
+            chcon --reference /dev/$node $dev_path/$node 2>/dev/null
+        done
+    fi
+}
+
+container_rootfs_create()
+{
+    if can_chcon; then
+        chcon --reference / $container_rootfs 2>/dev/null
+    fi
+
+    cmds="rpm wget yum"
+    for cmd in $cmds; do
+        which $cmd >/dev/null 2>&1
+        if [ $? -ne 0 ]; then
+            die "The $cmd command is required, please install it"
+        fi
+    done
+
+    mkdir -p @LOCALSTATEDIR@/lock/subsys
+    (
+        flock -x 9
+        if [ $? -ne 0 ]; then
+            die "The template is busy."
+        fi
+
+        echo "Yum installing release $container_release_major.$container_release_minor for $basearch"
+
+        if [ -n "$repourl" ]; then
+            yum_url=$repourl
+        else
+            yum_url=http://yum.oracle.com
+        fi
+
+        if [ -n "$baseurl" ]; then
+            # create .repo pointing at baseurl
+            repo="lxc-install"
+            mkdir -p $container_rootfs/etc/yum.repos.d
+            container_rootfs_repo_create \
+                $container_rootfs/etc/yum.repos.d/lxc-install.repo $repo $baseurl
+        else
+            # get public-yum repo file
+            if [ $container_release_major = "1" ]; then
+                repofile=yum-linux-sparc64.repo
+            else
+                die "Unsupported release $container_release_major"
+            fi
+
+            mkdir -p $container_rootfs/etc/yum.repos.d
+            wget -q $yum_url/$repofile -O $container_rootfs/etc/yum.repos.d/$repofile
+            if [ $? -ne 0 ]; then
+                die "Unable to download repo file $yum_url/$repofile, release unavailable"
+            fi
+
+            # yum will take $basearch from host, so force the arch we want
+            sed -i "s|\$basearch|$basearch|" $container_rootfs/etc/yum.repos.d/$repofile
+
+            # replace url if they specified one
+            if [ -n "$repourl" ]; then
+                sed -i "s|baseurl=http://yum.oracle.com/|baseurl=$repourl/repo|" $container_rootfs/etc/yum.repos.d/$repofile
+                sed -i "s|gpgkey=http://yum.oracle.com|gpgkey=$repourl|" $container_rootfs/etc/yum.repos.d/$repofile
+
+            fi
+
+            # disable all repos, then enable the repo for the version we are installing.
+            if [ $container_release_minor = "latest" ]; then
+                repo="lfs"_$container_release_minor
+            else
+                die "Unsupported release $container_release_major.$container_release_minor"
+            fi
+            sed -i "s|enabled=1|enabled=0|" $container_rootfs/etc/yum.repos.d/$repofile
+            sed -i "/\[$repo\]/,/\[/ s/enabled=0/enabled=1/" $container_rootfs/etc/yum.repos.d/$repofile
+        fi
+
+        container_rootfs_dev_create
+
+        # don't put devpts,proc, nor sysfs in here, it will already be mounted for us by lxc/libvirt
+        echo "" >$container_rootfs/etc/fstab
+
+        # create rpm db, download and yum install minimal packages
+        mkdir -p $container_rootfs/var/lib/rpm
+        rpm --root $container_rootfs --initdb
+        yum_args="--installroot $container_rootfs --disablerepo=* --enablerepo=$repo -y --nogpgcheck"
+        min_pkgs="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils sparclinux-release"
+
+        # we unshare the mount namespace because yum installing the ol4
+        # packages causes $rootfs/proc to be mounted on
+        lxc-unshare -s MOUNT yum -- $yum_args install $min_pkgs $user_pkgs
+        if [ $? -ne 0 ]; then
+            die "Failed to download and install the rootfs, aborting."
+        fi
+
+        # rsyslog and pam depend on coreutils for some common commands in
+        # their POSTIN scriptlets, but coreutils wasn't installed yet. now
+        # that coreutils is installed, reinstall the packages so their POSTIN
+        # runs right. similarly, libutempter depends on libselinux.so.1 when
+        # it runs /usr/sbin/groupadd, so reinstall it too
+        redo_pkgs=""
+        if [ x"$redo_pkgs" != x ]; then
+            rpm --root $container_rootfs --nodeps -e $redo_pkgs
+            lxc-unshare -s MOUNT yum -- $yum_args install $redo_pkgs
+            if [ $? -ne 0 ]; then
+                die "Unable to reinstall packages"
+            fi
+        fi
+
+        # these distributions put the rpm database in a place the guest is
+        # not expecting it, so move it
+        if [ $host_distribution = "Ubuntu" -o $host_distribution = "Debian" ]; then
+            mv $container_rootfs/$HOME/.rpmdb/* $container_rootfs/var/lib/rpm
+        fi
+
+        # if the native rpm created the db with Hash version 9, we need to
+        # downgrade it to Hash version 8 for use with OL5.x
+        db_version=`file $container_rootfs/var/lib/rpm/Packages | \
+                    grep -o 'version [0-9]*' |awk '{print $2}'`
+
+        # the host rpm may not be the same as the guest, rebuild the db with
+        # the guest rpm version
+        echo "Rebuilding rpm database"
+        rm -f $container_rootfs/var/lib/rpm/__db*
+        chroot $container_rootfs rpm --rebuilddb >/dev/null 2>&1
+
+    ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-sparclinux-$name
+    if [ $? -ne 0 ]; then
+        exit 1
+    fi
+}
+
+container_release_get()
+{
+    if [ -f $1/etc/sparclinux-release ]; then
+        container_release_version=`cat $1/etc/sparclinux-release |awk '/^Linux/ {print $5}'`
+        container_release_major=`echo $container_release_version |awk -F '.' '{print $1}'`
+        container_release_minor=`echo $container_release_version |awk -F '.' '{print $2}'`
+    else
+        echo "Unable to determine container release version"
+        exit 1
+    fi
+}
+
+usage()
+{
+    cat <<EOF
+  -a|--arch=<arch>        architecture (sparc64)
+  -R|--release=<release>  release to download for the new container
+  --rootfs=<path>         rootfs path
+  -r|--rpms=<rpm name>    additional rpms to install into container
+  -u|--url=<url>          replace yum repo url (ie. Oracle public-yum mirror)
+     --baseurl=<url>      use package repository (ie. file:///mnt)
+                          arch and release must also be specified
+  -t|--templatefs=<path>  copy/clone rootfs at path instead of downloading
+  -P|--patch=<path>       only patch the rootfs at path for use as a container
+  -h|--help
+
+Release is of the format "major.minor", for example "1.0" or "1.latest"
+This template supports Linux for SPARC release 1.0 
+EOF
+    return 0
+}
+
+options=$(getopt -o hp:n:a:R:r:u:t: -l help,rootfs:,path:,name:,arch:,release:,rpms:,url:,templatefs:,patch:,baseurl: -- "$@")
+if [ $? -ne 0 ]; then
+    usage $(basename $0)
+    exit 1
+fi
+
+eval set -- "$options"
+while true
+do
+    case "$1" in
+        -h|--help)             usage $0 && exit 0;;
+        -p|--path)             cfg_dir=$2; shift 2;;
+        --rootfs)              container_rootfs=$2; shift 2;;
+        -n|--name)             name=$2; shift 2;;
+        -a|--arch)             arch=$2; shift 2;;
+        -R|--release)          container_release_version=$2; shift 2;;
+        -r|--rpms)             user_pkgs=$2; shift 2;;
+        -u|--url)              repourl=$2; shift 2;;
+        -t|--templatefs)       template_rootfs=$2; shift 2;;
+        --patch)               patch_rootfs=$2; shift 2;;
+        --baseurl)             baseurl=$2; shift 2;;
+        --)                    shift 1; break ;;
+        *)                     break ;;
+    esac
+done
+
+# make sure mandatory args are given and valid
+if [ "$(id -u)" != "0" ]; then
+    echo "This script should be run as 'root'"
+    exit 1
+fi
+
+if [ -n "$baseurl" ]; then
+    if [ "$arch" = "" -o "$container_release_version" = "" ]; then
+        echo "The --arch and --release must be specified when using --baseurl"
+        usage
+        exit 1
+    fi
+fi
+
+if [ "$arch" = "" ]; then
+    arch=$(uname -m)
+fi
+
+if [ -n "$patch_rootfs" ]; then
+    container_rootfs="$patch_rootfs"
+    container_release_get $container_rootfs
+    container_rootfs_patch
+    exit 0
+fi
+
+if [ -z $name ]; then
+    echo "Container name must be given"
+    usage
+    exit 1
+fi
+
+if [ -z $cfg_dir ]; then
+    echo "Configuration directory must be given, check lxc-create"
+    usage
+    exit 1
+fi
+
+basearch=$arch
+
+if [ "$arch" != "sparc64" ]; then
+    echo "Bad architecture given, check lxc-create"
+    usage
+    exit 1
+fi
+
+if [ -f /etc/sparclinux-release ]; then
+   host_distribution="SPARCLinux"
+   host_release_version=`cat /etc/sparclinux-release |awk '{print $5}'`
+   host_release_major=`echo $host_release_version |awk -F '.' '{print $1}'`
+   host_release_minor=`echo $host_release_version |awk -F '.' '{print $2}'`
+else
+   echo "Unable to determine host distribution"
+   exit 1
+fi
+
+echo "Host is $host_distribution $host_release_version"
+
+if [ -z "$container_rootfs" ]; then
+    container_rootfs="$cfg_dir/rootfs"
+fi
+
+if [ -n "$template_rootfs" ]; then
+    container_release_get $template_rootfs
+else
+    if [ -z "$container_release_version" ]; then
+        if [ $host_distribution = "SPARCLinux" ]; then
+            container_release_version=$host_release_version
+        else
+            echo "No release specified with -R, defaulting to 1.latest"
+            container_release_version="1.latest"
+        fi
+    fi
+    container_release_major=`echo $container_release_version |awk -F '.' '{print $1}'`
+    container_release_minor=`echo $container_release_version |awk -F '.' '{print $2}'`
+fi
+
+container_config_create
+if [ -n "$template_rootfs" ]; then
+    container_rootfs_clone
+else
+    container_rootfs_create
+fi
+
+container_release_get $container_rootfs
+
+container_rootfs_configure
+
+echo "Container : $container_rootfs"
+echo "Config    : $cfg_dir/config"
+echo "Network   : eth0 ($lxc_network_type) on $lxc_network_link"
index d34b3b4..9b07ea6 100644 (file)
@@ -125,6 +125,8 @@ copy_configuration()
     rootfs=$2
     name=$3
 
+    init_path=$(realpath --relative-to=/ $(readlink -f /sbin/init))
+
     grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
 cat <<EOF >> $path/config
 lxc.utsname = $name
@@ -140,7 +142,7 @@ lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
 lxc.mount.entry = tmpfs var/run/sshd tmpfs mode=0644 0 0
-lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd sbin/init none ro,bind 0 0
+lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd $init_path none ro,bind 0 0
 lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0
 
 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
index 12fc594..0b53cb1 100644 (file)
@@ -25,7 +25,7 @@ STATE_DIR="@LOCALSTATEDIR@"
 HOOK_DIR="@LXCHOOKDIR@"
 CLONE_HOOK_FN="$HOOK_DIR/ubuntu-cloud-prep"
 LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
-KNOWN_RELEASES="precise trusty utopic vivid"
+KNOWN_RELEASES="precise trusty vivid wily xenial"
 skip_arch_check=${UCTEMPLATE_SKIP_ARCH_CHECK:-0}
 
 # Make sure the usual locations are in PATH
@@ -146,7 +146,7 @@ EOF
     return 0
 }
 
-options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds:u: -l arch:,help,rootfs:,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata:,mapped-uid:,mapped-gid: -- "$@")
+options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds:u: -l arch:,help,rootfs:,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata:,vendordata:,mapped-uid:,mapped-gid: -- "$@")
 if [ $? -ne 0 ]; then
     usage $(basename $0)
     exit 1
@@ -155,8 +155,8 @@ eval set -- "$options"
 
 mapped_uid=-1
 mapped_gid=-1
-# default release is precise, or the systems release if recognized
-release=precise
+# default release is trusty, or the systems release if recognized
+release=trusty
 if [ -f /etc/lsb-release ]; then
     . /etc/lsb-release
     rels=$(ubuntu-distro-info --supported 2>/dev/null) ||
@@ -179,7 +179,7 @@ else
         arch="amd64"
     elif [ "$arch" = "armv7l" ]; then
         # note: arm images don't exist before oneiric;  are called armhf in
-        # precise and later;  and are not supported by the query, so we don't actually
+        # trusty and later;  and are not supported by the query, so we don't actually
         # support them yet (see check later on).  When Query2 is available,
         # we'll use that to enable arm images.
         arch="armhf"
@@ -213,6 +213,7 @@ do
     -L|--no?locales)   cloneargs[${#cloneargs[@]}]="--no-locales"; shift 1;;
     -i|--hostid)       cloneargs[${#cloneargs[@]}]="--hostid=$2"; shift 2;;
     -u|--userdata)     cloneargs[${#cloneargs[@]}]="--userdata=$2"; shift 2;;
+    -V|--vendordata)   cloneargs[${#cloneargs[@]}]="--vendordata=$2"; shift 2;;
     -C|--cloud)        cloneargs[${#cloneargs[@]}]="--cloud"; shift 1;;
     -S|--auth-key)     cloneargs[${#cloneargs[@]}]="--auth-key=$2"; shift 2;;
     --mapped-uid)      mapped_uid=$2; shift 2;;
@@ -274,10 +275,11 @@ type wget
 
 # determine the url, tarball, and directory names
 # download if needed
-cache="$STATE_DIR/cache/lxc/cloud-$release"
+# Allow the cache base to be set by environment variable
+cache=${LXC_CACHE_PATH:-"$STATE_DIR/cache/lxc"}/cloud-$release
 if [ $in_userns -eq 1 ]; then
-    STATE_DIR="$HOME/.cache/lxc/"
-    cache="$HOME/.cache/lxc/cloud-$release"
+    STATE_DIR="$HOME/.cache/lxc"
+    cache=${LXC_CACHE_PATH:-"$STATE_DIR"}/cloud-$release
 fi
 
 mkdir -p $cache
@@ -326,10 +328,10 @@ do_extract_rootfs() {
     mkdir -p $rootfs
     cd $rootfs
     if [ $in_userns -eq 1 ]; then
-        tar --anchored --exclude="dev/*" --numeric-owner -xpJf "$cache/$filename"
+        tar --anchored --exclude="dev/*" --numeric-owner -xpf "$cache/$filename"
         mkdir -p $rootfs/dev/pts/
     else
-        tar --numeric-owner -xpJf "$cache/$filename"
+        tar --numeric-owner -xpf "$cache/$filename"
     fi
 }
 
index 55199dc..06ce8ce 100644 (file)
@@ -41,6 +41,8 @@ set -e
 
 LOCALSTATEDIR="@LOCALSTATEDIR@"
 LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
+# Allows the lxc-cache directory to be set by environment variable
+LXC_CACHE_PATH=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc"}
 
 if [ -r /etc/default/lxc ]; then
     . /etc/default/lxc
@@ -329,7 +331,19 @@ download_ubuntu()
     arch=$2
     release=$3
 
+    case $2 in
+      amd64|i386)
+            MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
+            SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
+            ;;
+      *)
+            MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
+            SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
+            ;;
+    esac
+
     packages_template=${packages_template:-"ssh,vim"}
+    debootstrap_parameters=
 
     # Try to guess a list of langpacks to install
     langpacks="language-pack-en"
@@ -341,6 +355,12 @@ download_ubuntu()
     fi
     packages_template="${packages_template},$(echo $langpacks | sed 's/ /,/g')"
 
+    if [ -n "$variant" ]; then
+        debootstrap_parameters="$debootstrap_parameters --variant=$variant"
+    fi
+    if [ "$variant" = 'minbase' ]; then
+        packages_template="${packages_template},sudo,ifupdown,isc-dhcp-client"
+    fi
 
     echo "Installing packages in template: ${packages_template}"
 
@@ -356,9 +376,9 @@ download_ubuntu()
     # download a mini ubuntu into a cache
     echo "Downloading ubuntu $release minimal ..."
     if [ -n "$(which qemu-debootstrap)" ]; then
-        qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
+        qemu-debootstrap --verbose $debootstrap_parameters --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
     else
-        debootstrap --verbose --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
+        debootstrap --verbose $debootstrap_parameters --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
     fi
 
     if [ $? -ne 0 ]; then
@@ -423,7 +443,7 @@ install_ubuntu()
     rootfs=$1
     release=$2
     flushcache=$3
-    cache="$LOCALSTATEDIR/cache/lxc/$release"
+    cache="$4/$release"
     mkdir -p $LOCALSTATEDIR/lock/subsys/
 
     (
@@ -645,10 +665,11 @@ usage()
 {
     cat <<EOF
 $1 -h|--help [-a|--arch] [-b|--bindhome <user>] [-d|--debug]
-   [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
+   [-F | --flush-cache] [-r|--release <release>] [-v|--variant] [ -S | --auth-key <keyfile>]
    [--rootfs <rootfs>] [--packages <packages>] [-u|--user <user>] [--password <password>]
    [--mirror <url>] [--security-mirror <url>]
 release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
+variant: debootstrap variant to use (see debootstrap(8))
 bindhome: bind <user>'s home into the container
           The ubuntu user will not be created, and <user> will have
           sudo access.
@@ -660,7 +681,7 @@ EOF
     return 0
 }
 
-options=$(getopt -o a:b:hp:r:n:FS:du: -l arch:,bindhome:,help,path:,release:,name:,flush-cache,auth-key:,debug,rootfs:,packages:,user:,password:,mirror:,security-mirror: -- "$@")
+options=$(getopt -o a:b:hp:r:v:n:FS:du: -l arch:,bindhome:,help,path:,release:,variant:,name:,flush-cache,auth-key:,debug,rootfs:,packages:,user:,password:,mirror:,security-mirror: -- "$@")
 if [ $? -ne 0 ]; then
     usage $(basename $0)
     exit 1
@@ -703,6 +724,7 @@ flushcache=0
 packages=""
 user="ubuntu"
 password="ubuntu"
+
 while true
 do
     case "$1" in
@@ -714,6 +736,7 @@ do
     --password)     password=$2; shift 2;;
     -F|--flush-cache) flushcache=1; shift 1;;
     -r|--release)   release=$2; shift 2;;
+    -v|--variant)   variant=$2; shift 2;;
     --packages)     packages=$2; shift 2;;
     -b|--bindhome)  bindhome=$2; shift 2;;
     -a|--arch)      arch=$2; shift 2;;
@@ -787,7 +810,7 @@ if [ -z "$rootfs" ]; then
     fi
 fi
 
-install_ubuntu $rootfs $release $flushcache
+install_ubuntu $rootfs $release $flushcache $LXC_CACHE_PATH
 if [ $? -ne 0 ]; then
     echo "failed to install ubuntu $release"
     exit 1